device tree overlay phandle - linux-kernel

I'm working on a Cyclone V SOC FPGA from Altera with a double Cortex-A9 processor. The embedded system (linux-socfpga 4.16) is created with Buildroot-2018.05.
I use a "top" device tree at boot time for processor component and a device-tree overlay to configure the FPGA part of the component and load the associated drivers. The overlay will be attach to the base_fpga_region of the top DT.
top device tree
/dts-v1/;
/ {
model = "MY_PROJECT"; /* appended from boardinfo */
compatible = "altr,socfpga-cyclone5", "altr,socfpga"; /* appended from boardinfo */
#address-cells = <1>;
#size-cells = <1>;
cpus {
[...]
}; //end cpus
memory {
device_type = "memory";
reg = <0xffff0000 0x00010000>,
<0x00000000 0x80000000>;
}; //end memory
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
mem_dma_reserved {
compatible = "shared-dma-pool";
no-map;
reg = <0x78000000 0x8000000>;
};
};
soc: soc {
device_type = "soc";
ranges;
#address-cells = <1>;
#size-cells = <1>;
compatible = "altr,avalon", "simple-bus";
bus-frequency = <0>;
fpgabridge1: fpgabridge#1 {
compatible = "altr,socfpga-lwhps2fpga-bridge";
resets = <&hps_rstmgr 97>; /* appended from boardinfo */
clocks = <&l4_main_clk>; /* appended from boardinfo */
#address-cells = <1>;
#size-cells = <1>;
ranges;
bridge-enable = <1>;
label = "lwhps2fpga";
reset-names = "lwhps2fpga";
reg = <0xff200000 0x200000>;
reg-names = "axi_h2f_lw";
}; //end fpgabridge#1 (fpgabridge1)
base_fpga_region: base_fpga_region {
compatible = "fpga-region";
#address-cells = <0x2>;
#size-cells = <0x1>;
fpga-mgr = <&hps_fpgamgr>;
fpga-bridges = <&fpgabridge1>;
ranges = <0x0 0x0 0xff200000 0x200000>;
}; //end base_fpga_region (base_fpga_region)
etc......
Device tree overlay
/dts-v1/ /plugin/;
/{
fragment#0 {
target-path = "/soc/base_fpga_region";
#address-cells = <2>;
#size-cells = <1>;
__overlay__ {
#address-cells = <2>;
#size-cells = <1>;
firmware-name = "my_project.rbf";
my_dma_0: dma#0x000000000 {
compatible = "my_company,my_dma-0.1";
reg = <0x00000000 0x0000000 0x00000014>;
memory-region = <&mem_dma_reserved>;
}; //end dma#0x000000000 (my_dma_0)
};
};
};
my problem is to link the mem_dma_reserved from the top DT to the memory-region in the overlay.
I assume that while converting dts to dtbo with the -# option, the overlay shall get the phandle for mem_dma_reserved with the __fixups__ option. I've created the dtbo file and converted it again in dts to see what is done during the compilation :
dtc -# -I dts -O dtb -o overlay.dtbo overlay.dts
dtc -I dtb -O dts -o overlay_recovery.dts overlay.dtbo
device tree overlay regenerated
/dts-v1/;
/ {
fragment#0 {
target-path = "/soc/base_fpga_region";
#address-cells = <0x2>;
#size-cells = <0x1>;
__overlay__ {
#address-cells = <0x2>;
#size-cells = <0x1>;
firmware-name = "my_project.rbf";
dma#0x000000000 {
compatible = "my_company,my_dma-0.1";
reg = <0x0 0x0 0x14>;
memory-region = <0xffffffff>; // phandle converted to 0xffffffff, cannot resolve unless the __fixup__ function does it.
linux,phandle = <0x2>;
phandle = <0x2>;
};
};
};
__symbols__ {
my_dma_0 = "/fragment#0/__overlay__/dma#0x000000000";
};
__fixups__ {
mem_dma_reserved = "/fragment#0/__overlay__/dma#0x000000000:memory-region:0";
};
};
We can see that the phandle for the memory-region is 0xFFFFFFFF because the overlay doesn't know about the <&mem_dma_reserved> node. the fixup part shall be able to get back the phandle at loading time, but it isn't working and I get this error :
[ 27.434730] OF: resolver: of_resolve_phandles: no symbols in root of device tree.
[ 27.440401] OF: resolver: overlay phandle fixup failed: -22
[ 27.445993] create_overlay: Failed to resolve tree
I have made the same regeneration from dtb to dts on the top DT. I have seen that the phandle of the reserved memory is actually 0x6. I have written <0x6> instead of <&mem_dma_reserved> in the device tree overlay and with this configuration, everything loads !
How can I make the overlay find the <&mem_dma_reserved> automatically without doing it by hand ?
EDIT
As pointed by ikwzm I have added in the top device tree the following lines :
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
mem_dma_reserved: mem_dma_reserved { // add a label
compatible = "shared-dma-pool";
no-map;
reg = <0x78000000 0x8000000>;
};
};
[...]
// add the whole symbol block
__symbols__ {
mem_dma_reserved = "/reserved-memory/mem_dma_reserved ";
};
The errors are now gone, but :
I was expecting the driver for my_dma to be loaded during the operation.
I checked that the device tree overlay is well taken into account with :
ls /sys/firmware/devicetree/base/soc/base_fpga_region/
my_dma_0
other_stuff
cat /sys/firmware/devicetree/base/soc/base_fpga_region/my_dma_0/memory-region
//nothing//
The memory region doesn't seem to be attached.
What I have missed ?

When making the top dtb, did you attach the option --symbol (or -#) to the dtc command?
Add a label (symbol) to mem_dma_reserved as follows.
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
mem_dma_reserved: mem_dma_reserved {
compatible = "shared-dma-pool";
no-map;
reg = <0x78000000 0x8000000>;
};
};
When dtb is created with the --symbol option dtc command, __symbols__{...}; is added as follows, and mem_dma_reserved = "/reserved-memory/ mem_dma_reserved"; should be found in it.
__symbols__ {
:
:
:
mem_dma_reserved = "/reserved-memory/mem_dma_reserved";
usb_phy0 = "/phy0";
};

Related

How to use gpio from device tree in a i2c_driver?

I've written an I2C driver. I want to make the GPIO which it uses configurable from the device tree.
My device tree entry is currently:
&i2c1 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
status = "okay";
...
myi2c: myi2c#43 {
compatible = "fsl,myi2c";
reg = <0x43>;
};
I'd like to add this line into the myi2c stanza:
myi2c-gpios = <&gpio4 29 GPIO_ACTIVE_HIGH>;
I can see how to do this, if I was writing a platform driver:
static int gpio_init_probe(struct platform_device *pdev)
{
int i = 0;
printk("GPIO example init\n");
/* "greenled" label is matching the device tree declaration. OUT_LOW is the value at init */
green = devm_gpiod_get(&pdev->dev, "greenled", GPIOD_OUT_LOW);
but in my driver's i2c_probe(), I have no access to a struct platform_device *:
static int myi2c_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
How can I read the value of myi2c-gpios from the device tree and use it in my i2c driver?
I found this driver to use as an example:
static int sn65dsi84_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
...
struct gpio_desc *enable_gpio;
enable_gpio = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_HIGH);
if (enable_gpio)
gpiod_set_value_cansleep(enable_gpio, 1);
and its device tree is:
&i2c2 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c2>;
status = "okay";
dsi_lvds_bridge: sn65dsi84#2c {
status = "disabled";
reg = <0x2c>;
compatible = "ti,sn65dsi84";
enable-gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>;
So devm_gpiod_get_optional() seems to be the answer.

Sharing variable between nodes in a device tree

I'm trying to find a way to accesses, from node_1, a variable in node_0 (see code below) in this device-tree:
/ {
amba_pl: amba_pl#0 {
node_0: node#a8000000 {
node_id = <0x0>;
node0State = <0x0>;
};
};
node_1: node#a9000000 {
node1State = <node_0's node0State>;
};
};
};
The primary goal is to be able to share a state between kernel modules. I'm aware that I can EXPORT_SYMBOL(variable) in the writing node and then extern *variable in the reading node, but wanted to see if I could accomplish this in the device-tree itself. node_0 would always be the only node to set the nodeState, and node_1 would only read. Is this possible?
You can store a phandle referring to the node containing node0state:
/ {
amba_pl: amba_pl#0 {
node_0: node#a8000000 {
node_id = <0x0>;
node0State = <0x0>;
};
};
node_1: node#a9000000 {
stateNode = <&node_0>;
};
};
};
In the driver code, if struct device_node *mynode; refers to the node_1 node, the node0state property of the other node referred to by the stateNode phandle property can be accessed as follows:
int rc = 0;
struct device_node *np;
u32 node0state;
np = of_parse_phandle(mynode, "stateNode", 0);
if (!np) {
// error node not found
rc = -ENXIO;
goto error1;
}
// Do whatever is needed to read "node0state". Here is an example.
rc = of_property_read_u32(np, "node0state", &node0state);
if (rc) {
// error
of_node_put(np); // decrement reference to the node
goto error2;
}
// Finished with the node.
of_node_put(np); // decrement reference to the node

Linux PCI device interrupt not generated

I am currently refactoring a driver for the AMD Sensor Fusion Hub.
The original driver can be found here.
When sending commands to the device, the chip takes some time to process the request. I wasusing a hack using msleep to wait for the device to respond. However I'd like to cleanly implement IRQ handling. As a template I looked into the implementation of drivers/i2c/busses/i2c-amd-mp2-pci.c and came up with the following stub interrupt handling.
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* AMD Sensor Fusion Hub (SFH) PCIe driver
*
* Authors: Shyam Sundar S K <Shyam-sundar.S-k#amd.com>
* Nehal Bakulchandra Shah <Nehal-bakulchandra.Shah#amd.com>
* Richard Neumann <mail#richard-neumann.de>
*/
#include <linux/bitops.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/types.h>
#include "amd-sfh-pci.h"
/**
* amd_sfh_get_sensor_mask - Returns the sensors mask.
* #pci_dev: The Sensor Fusion Hub PCI device
*
* Returns an unsigned integer representing the bitmask to match
* the sensors connected to the Sensor Fusion Hub.
*/
int amd_sfh_get_sensor_mask(struct pci_dev *pci_dev)
{
int sensor_mask;
struct amd_sfh_dev *sfh_dev = pci_get_drvdata(pci_dev);
sensor_mask = readl(sfh_dev->mmio + AMD_SFH_SENSOR_MASK);
/* Correct bit shift in firmware register */
sensor_mask = sensor_mask >> 4;
if (!sensor_mask)
dev_err(&pci_dev->dev, "no sensors marked active on device\n");
return sensor_mask;
}
EXPORT_SYMBOL_GPL(amd_sfh_get_sensor_mask);
/**
* amd_sfh_start_sensor- Starts the respective sensor.
* #pci_dev: The Sensor Fusion Hub PCI device
* #sensor_idx: The sensor's index
* #dma_handle: The DMA handle
*/
void amd_sfh_start_sensor(struct pci_dev *pci_dev, enum sensor_idx sensor_idx,
dma_addr_t dma_handle)
{
struct amd_sfh_dev *sfh_dev = pci_get_drvdata(pci_dev);
union amd_sfh_cmd command;
union amd_sfh_parm parameter;
command.ul = 0;
command.s.cmd_id = enable_sensor;
command.s.period = PERIOD;
command.s.sensor_id = sensor_idx;
parameter.ul = 0;
parameter.s.buffer_layout = 1;
parameter.s.buffer_length = 16;
writeq(dma_handle, sfh_dev->mmio + AMD_SFH_ADDR);
writel(parameter.ul, sfh_dev->mmio + AMD_SFH_PARM);
writel(command.ul, sfh_dev->mmio + AMD_SFH_CMD);
}
EXPORT_SYMBOL_GPL(amd_sfh_start_sensor);
/**
* amd_sfh_stop_sensor- Stops the respective sensor.
* #pci_dev: The Sensor Fusion Hub PCI device
* #sensor_idx: The sensor's index
*/
void amd_sfh_stop_sensor(struct pci_dev *pci_dev, enum sensor_idx sensor_idx)
{
struct amd_sfh_dev *sfh_dev = pci_get_drvdata(pci_dev);
union amd_sfh_cmd command;
command.ul = 0;
command.s.cmd_id = disable_sensor;
command.s.period = 0;
command.s.sensor_id = sensor_idx;
writeq(0x0, sfh_dev->mmio + AMD_SFH_ADDR);
writel(command.ul, sfh_dev->mmio + AMD_SFH_CMD);
}
EXPORT_SYMBOL_GPL(amd_sfh_stop_sensor);
/**
* amd_sfh_stop_all_sensors- Stops all sensors on the SFH.
* #pci_dev: The Sensor Fusion Hub PCI device
*/
static void amd_sfh_stop_all_sensors(struct pci_dev *pci_dev)
{
struct amd_sfh_dev *sfh_dev = pci_get_drvdata(pci_dev);
union amd_sfh_cmd command;
command.ul = 0;
command.s.cmd_id = stop_all_sensors;
command.s.period = 0;
command.s.sensor_id = 0;
writel(command.ul, sfh_dev->mmio + AMD_SFH_CMD);
}
/**
* amd_sfh_irq_isr - IRQ handler
* #irq: The IRQ number received
* #dev: The underlying device
*/
static irqreturn_t amd_sfh_irq_isr(int irq, void *dev)
{
struct amd_sfh_dev *sfh_dev = dev;
dev_info(&sfh_dev->pci_dev->dev, "got IRQ: %d\n", irq);
return IRQ_NONE;
}
/**
* amd_sfh_pci_init - Initializes the PCI device
* #sfh_dev: The device data
* #pci_dev: The PCI device
*/
static int amd_sfh_pci_init(struct amd_sfh_dev *sfh_dev,
struct pci_dev *pci_dev)
{
int rc;
pci_set_drvdata(pci_dev, sfh_dev);
rc = pcim_enable_device(pci_dev);
if (rc)
goto err_pci_enable;
rc = pcim_iomap_regions(pci_dev, BIT(2), pci_name(pci_dev));
if (rc)
goto err_pci_enable;
sfh_dev->pci_dev = pci_dev;
sfh_dev->mmio = pcim_iomap_table(pci_dev)[2];
pci_set_master(pci_dev);
rc = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(64));
if (rc) {
rc = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
if (rc)
goto err_dma_mask;
}
/* Set up intx irq */
writel(0, sfh_dev->mmio + AMD_P2C_MSG_INTEN);
pci_intx(pci_dev, 1);
dev_info(&pci_dev->dev, "available interrupt: %d\n", pci_dev->irq);
rc = devm_request_irq(&pci_dev->dev, pci_dev->irq, amd_sfh_irq_isr,
0, dev_name(&pci_dev->dev), sfh_dev);
if (rc)
dev_err(&pci_dev->dev, "Failure requesting irq %i: %d\n",
pci_dev->irq, rc);
return rc;
err_dma_mask:
pci_clear_master(pci_dev);
err_pci_enable:
return rc;
}
static int amd_sfh_pci_probe(struct pci_dev *pci_dev,
const struct pci_device_id *id)
{
int rc;
struct amd_sfh_dev *sfh_dev;
sfh_dev = devm_kzalloc(&pci_dev->dev, sizeof(*sfh_dev), GFP_KERNEL);
if (!sfh_dev)
return -ENOMEM;
rc = amd_sfh_pci_init(sfh_dev, pci_dev);
if (rc)
return rc;
pm_runtime_set_autosuspend_delay(&pci_dev->dev, 1000);
pm_runtime_use_autosuspend(&pci_dev->dev);
pm_runtime_put_autosuspend(&pci_dev->dev);
pm_runtime_allow(&pci_dev->dev);
dev_info(&pci_dev->dev, "SFH device registered.\n");
return 0;
}
static void amd_sfh_pci_remove(struct pci_dev *pci_dev)
{
struct amd_sfh_dev *sfh_dev = pci_get_drvdata(pci_dev);
amd_sfh_stop_all_sensors(sfh_dev->pci_dev);
pm_runtime_forbid(&pci_dev->dev);
pm_runtime_get_noresume(&pci_dev->dev);
pci_intx(pci_dev, 0);
pci_clear_master(pci_dev);
}
static const struct pci_device_id amd_sfh_pci_tbl[] = {
{PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_SFH)},
{0}
};
MODULE_DEVICE_TABLE(pci, amd_sfh_pci_tbl);
static struct pci_driver amd_sfh_pci_driver = {
.name = "amd-sfh-pci",
.id_table = amd_sfh_pci_tbl,
.probe = amd_sfh_pci_probe,
.remove = amd_sfh_pci_remove,
};
module_pci_driver(amd_sfh_pci_driver);
/**
* amd_sfh_find_device - Returns the first best AMD SFH device.
*/
struct amd_sfh_dev *amd_sfh_find_device(void)
{
struct device *dev;
struct pci_dev *pci_dev;
dev = driver_find_next_device(&amd_sfh_pci_driver.driver, NULL);
if (!dev)
return NULL;
pci_dev = to_pci_dev(dev);
return pci_get_drvdata(pci_dev);
}
EXPORT_SYMBOL_GPL(amd_sfh_find_device);
MODULE_DESCRIPTION("AMD(R) Sensor Fusion Hub PCI driver");
MODULE_AUTHOR("Shyam Sundar S K <Shyam-sundar.S-k#amd.com>");
MODULE_AUTHOR("Nehal Bakulchandra Shah <Nehal-bakulchandra.Shah#amd.com>");
MODULE_AUTHOR("Richard Neumann <mail#richard-neumann.de>");
MODULE_LICENSE("Dual BSD/GPL");
However the dev_info from amd_sfh_irq_isr is never logged, so I suspect that the IRQ is never triggered when writing to the device registers. What can be the reason for that and what can I do to correctly implement the IRQ handling?
PS
dmesg output:
[ 2272.642762] amd-sfh-pci 0000:04:00.7: available interrupt: 56
[ 2272.642840] amd-sfh-pci 0000:04:00.7: SFH device registered.
Update
The device seems to support MSI:
04:00.7 Non-VGA unclassified device [0000]: Advanced Micro Devices, Inc. [AMD] Raven/Raven2/Renoir Sensor Fusion Hub [1022:15e4]
Subsystem: Hewlett-Packard Company Raven/Raven2/Renoir Sensor Fusion Hub [103c:8496]
Flags: bus master, fast devsel, latency 0, IRQ 56
Memory at fc800000 (32-bit, non-prefetchable) [size=1M]
Memory at fcc8c000 (32-bit, non-prefetchable) [size=8K]
Capabilities: [48] Vendor Specific Information: Len=08 <?>
Capabilities: [50] Power Management version 3
Capabilities: [64] Express Endpoint, MSI 00
Capabilities: [a0] MSI: Enable- Count=1/2 Maskable- 64bit+
Capabilities: [c0] MSI-X: Enable- Count=2 Masked-
Capabilities: [100] Vendor Specific Information: ID=0001 Rev=1 Len=010 <?>
Kernel modules: amd_sfh_pci
But the interrupts are still not received / handled:
static void amd_sfh_debug(struct pci_dev *pci_dev)
{
bool msi;
msi = pci_dev_msi_enabled(pci_dev);
pci_info(pci_dev, "MSI: %s\n", msi ? "true" : "false");
pci_info(pci_dev, "No MSI: %s\n", pci_dev->no_msi ? "true" : "false");
}
/**
* amd_sfh_handle_irq - Handles IRQs.
* #irq: The interrupt request to be handled
* #dev: The driver data
*
* Returns an appropriate IRQ return type.
*/
static irqreturn_t amd_sfh_handle_irq(int irq, void *dev)
{
struct amd_sfh_dev *privdata = dev;
pci_info(privdata->pci_dev, "got IRQ: %d\n", irq);
return IRQ_NONE;
}
static int amd_sfh_setup_irq(struct amd_sfh_dev *privdata)
{
int rc, vecs, irq;
struct pci_dev *pci_dev = privdata->pci_dev;
vecs = pci_alloc_irq_vectors(pci_dev, 1, 3, PCI_IRQ_ALL_TYPES);
if (vecs < 0)
return vecs;
pci_info(pci_dev, "allocated %d IRQ vectors\n", vecs);
for (irq = 0; irq < vecs; irq++) {
pci_info(pci_dev, "requesting IRQ: %d\n", irq);
rc = devm_request_irq(&pci_dev->dev,
pci_irq_vector(pci_dev, irq),
amd_sfh_handle_irq, 0, "sfh-irq",
privdata);
if (rc) {
pci_err(pci_dev, "failed to get IRQ\n");
goto free_irq_vectors;
}
}
return 0;
free_irq_vectors:
pci_free_irq_vectors(pci_dev);
return rc;
}
static int amd_sfh_pci_init(struct amd_sfh_dev *privdata,
struct pci_dev *pci_dev)
{
int rc;
pci_set_drvdata(pci_dev, privdata);
rc = pcim_enable_device(pci_dev);
if (rc)
return rc;
rc = pcim_iomap_regions(pci_dev, BIT(2), pci_name(pci_dev));
if (rc)
return rc;
privdata->pci_dev = pci_dev;
privdata->mmio = pcim_iomap_table(pci_dev)[2];
pci_set_master(pci_dev);
rc = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(64));
if (rc) {
rc = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
if (rc)
goto clear_master;
}
/* Setup IRQ */
amd_sfh_debug(pci_dev);
rc = amd_sfh_setup_irq(privdata);
if (rc)
goto clear_master;
amd_sfh_debug(pci_dev);
/* End of IRQ setup */
pci_info(pci_dev, "AMD Sensor Fusion Hub device initialized\n");
return 0;
clear_master:
pci_clear_master(pci_dev);
return rc;
}
dmesg:
[ 6.954524] amd-sfh-pci 0000:04:00.7: enabling device (0000 -> 0002)
[ 6.954641] amd-sfh-pci 0000:04:00.7: MSI: false
[ 6.954642] amd-sfh-pci 0000:04:00.7: No MSI: false
[ 6.954791] amd-sfh-pci 0000:04:00.7: allocated 2 IRQ vectors
[ 6.954792] amd-sfh-pci 0000:04:00.7: requesting IRQ: 0
[ 6.954825] amd-sfh-pci 0000:04:00.7: requesting IRQ: 1
[ 6.954860] amd-sfh-pci 0000:04:00.7: MSI: true
[ 6.954861] amd-sfh-pci 0000:04:00.7: No MSI: false
[ 6.954861] amd-sfh-pci 0000:04:00.7: AMD Sensor Fusion Hub device initialized
[ 6.969691] amd-sfh-pci 0000:04:00.7: [Firmware Bug]: No sensors marked active!
[ 6.971265] amd-sfh-pci 0000:04:00.7: sensor mask: 0x000001
[ 7.548189] hid-generic 0018:03FE:0001.0001: hidraw0: I2C HID v0.01 Device [amd-sfh-accel] on
The original documentation from AMD mentiones interrupts but is not too specific as to how they are being generated.
By try-and-error I found that I needed to set the P2C register 0x10690 to 1 in order to enable interrupts on the device. Whith this set, the device is flooding the driver with interrupts. I'm still figuring out how to make the device generate interrupts only on actual write events to the C2P registers.
Okay, I found out, how:
https://github.com/conqp/linux/blob/5ba797452a794100d65d103e8eb53f64ae14d1d0/drivers/hid/amd-sfh-hid/amd-sfh-pci.c#L301

Define gpio in device tree

I have a Ti's AM335x custom board. I want to define some pins as gpios and be able to set them as input and output in its Linux userspace.
I defined pins in am33xx_pinmux and then referenced it with the bone-pinmux-helper. The problem is I can set it with these commands on the terminal but it doesn't work.
echo 4 > /sys/class/gpios/export
echo out > /sys/class/gpios/gpio4/direction
echo 1 > /sys/class/gpios/value
here is a brief of my code for just two pins gpio0_4 gpio0_5, each pin must become available to set as input or output in userspace.
#include "am33xx.dtsi"
#include <dt-bindings/interrupt-controller/irq.h>
&am33xx_pinmux {
pinctrl-names = "default";
DATA_OUT_A00:DATA_OUT_A00 {
pinctrl-single,pins = <0x158 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) >; /*gpio0_4*/
};
DATA_OUT_A01:DATA_OUT_A01 {
pinctrl-single,pins = <0x15C (PIN_OUTPUT_PULLDOWN | MUX_MODE7) >; /*gpio0_5*/
};
...
}
...
&ocp {
test_helper: helper {
compatible = "bone-pinmux-helper";
status = "okay";
pinctrl-names = "DATA_OUT_A00", "DATA_OUT_A01";
pinctrl-0 = <&DATA_OUT_A00>;
pinctrl-1 = <&DATA_OUT_A01>;
}
}
EDIT:-------------------
I'm using main Ti kernel 4.9 version. If I want to define these two pins as output this DTS works fine but ONLY for output mode. I can export pins as input but when I read its value it always returns zero.
#include "am33xx.dtsi"
#include <dt-bindings/interrupt-controller/irq.h>
/ {
model = "My Custom board C335x";
compatible = "ti,am33xx";
cpus {
cpu#0 {
cpu0-supply = <&vdd_core>;
};
};
...
gpio-leds {
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&led_pins>;
// the following two blocks make the pins available in /sys/class/leds
// if removed can be accessd with /sys/class/gpios
test_led1 {
label = "test";
gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
test_led2 {
label = "test";
gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
};
}
&am33xx_pinmux {
pinctrl-names = "default";
led_pins: pinmux_led_pins {
pinctrl-single,pins = <
0x158 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /*gpio0_4*/
0x15C (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /*gpio0_5*/
>;
};
...
}
If I leave these pins in the DTS file, I still can export them but I can't get any input or set a value as output to them.

Building I2C Structs

Hello I am looking at this documentation.
https://www.kernel.org/doc/html/v4.11/driver-api/i2c.html
My goal is simply to write some data to an EEPROM using an I2C bus. I am a bit confused on which functions to use and how to populate the structures that are needed for those functions.
My guess is that I will need to create an i2c_client to represent the EEPROM. I have the location of the EEPROM from this device tree.
&i2c0 {
status = "okay";
clock-frequency = <400000>;
pinctrl-names = "default";
i2cswitch#74 {
compatible = "nxp,pca9548";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x74>;
i2c#2 {
#address-cells = <1>;
#size-cells = <0>;
reg = <2>;
eeprom#54 {
compatible = "at,24c08";
reg = <0x54>;
};
};
};
};
How would I go about filling the i2c_client struct with this data?
Then I am guessing I would use this function
int i2c_master_send(const struct i2c_client * client, const char * buf, int count)
And provid it the client struct and a string that I want to write as well as the length of that string with the stipulation it is less than 64k. In this case the CPU is the master?
What header files will I need to included to use the functions and structs that are provided by the documentation?
Thanks.

Resources