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.
Related
Hello fellow developers,
I am developing a Linux kernel module that uses a DMA channel to transfer memory
(on STM32MP157F).
This works but additional tuning should be made. The STM mdma kernel module makes this possible by using this private configuration struct:
struct stm32_mdma_chan_config {
u32 request;
u32 priority_level;
u32 transfer_config;
u32 mask_addr;
u32 mask_data;
bool m2m_hw;
};
I would like set the priority from 0x0 to 0x3 which is its maximum allowed value.
The variable priority_level is set in stm32_mdma_of_xlate function:
static struct dma_chan *stm32_mdma_of_xlate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma)
{
struct stm32_mdma_chan_config config;
config.request = dma_spec->args[0];
config.priority_level = dma_spec->args[1];
....
}
Other modules/drivers in the system use a device tree setting like this for its and the used DMA channel configuration.
spi#44004000 {
#address-cells = <0x01>;
#size-cells = <0x00>;
dmas = <0x0e 0x25 0x400 0x01 0x0e 0x26 0x400 0x01>;
dma-names = "rx\0tx";
};
spi-stm32.c calls of_match_device in its stm32_spi_probe function. I believe the dma configuration is done during its execution.
I would like something similar for my character device driver:
mydriver#0 {
compatible = "mydriver";
dmas = <&mdma1 36 0x0 0x40008 0x0 0x0>,
<&mdma1 37 0x0 0x40002 0x0 0x0>;
dma-names = "rx", "tx";
};
But this is currently ignored because I do not have a platform device I could use to call
of_match_device. I seem to be blinded by to much source code to look at ...
Any tips for me?
Update:
Currently studying http://xillybus.com/tutorials/device-tree-zynq-3
Best regards Gunther
I solved my issues after doing some extra research.
These are the steps:
I had to add a custom entry to the device tree:
mydriver_0: mydriver#0 {
compatible = "mydriver";
dmas = <&mdma1 22 0x3 0x1200000a 0x48001008 0x00000020 1>;
dma-names = "dma0";
};
Make the driver loadable as a platform driver. Create an of_device_id match table matching the device tree entry. Change module_init() to call platform_driver_register() to register the matching table. Then implement a probe function calling the previous init function. Store pdev.
static int mydriver_drv_probe(struct platform_device *pdev)
{
// store pdev for later call to: dma_channel_req(&pdev->dev, "dma0");
// TODO init driver
return 0;
}
/* Connection to device tree */
static struct of_device_id mydriver_of_match[] =
{
{ .compatible = "mydriver" },
{}
};
MODULE_DEVICE_TABLE(of, mydriver_of_match);
static struct platform_driver mydriver_platform_driver = {
.probe = mydriver_drv_probe,
.remove = mydriver_drv_remove,
.driver = {
.name = "mydriver",
.owner = THIS_MODULE,
.of_match_table = mydriver_of_match,
},
};
static int __init _mydriver_driver_init(void)
{
return platform_driver_register(&mydriver_platform_driver);
}
module_init(_mydriver_driver_init);
Get the correctly configured DMA channel:
chan = dma_request_chan(&pdev->dev, "dma0");
I tested this and it worked. The requested DMA channel is configured using the my device tree "dmas" entry.
I hope this of use for somebody else!
I can't understand how the device tree information is used in a specific driver.
This is a code snippet from linux-5.15.68 drivers/pci/controller/dwc/pcie-designware-plat.c.
static int dw_plat_pcie_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct dw_plat_pcie *dw_plat_pcie;
struct dw_pcie *pci;
int ret;
const struct of_device_id *match;
const struct dw_plat_pcie_of_data *data;
enum dw_pcie_device_mode mode;
match = of_match_device(dw_plat_pcie_of_match, dev);
if (!match)
return -EINVAL;
data = (struct dw_plat_pcie_of_data *)match->data;
mode = (enum dw_pcie_device_mode)data->mode;
... (skip)
return 0;
}
static const struct dw_plat_pcie_of_data dw_plat_pcie_rc_of_data = {
.mode = DW_PCIE_RC_TYPE,
};
static const struct dw_plat_pcie_of_data dw_plat_pcie_ep_of_data = {
.mode = DW_PCIE_EP_TYPE,
};
static const struct of_device_id dw_plat_pcie_of_match[] = {
{
.compatible = "snps,dw-pcie",
.data = &dw_plat_pcie_rc_of_data,
},
{
.compatible = "snps,dw-pcie-ep",
.data = &dw_plat_pcie_ep_of_data,
},
{},
};
So the kernel parses the device tree (connected to the struct dev) while running this probe function for a platform device. It compares the 'compatible' field of the device tree's node with the match data of this driver (=dw_plat_pcie_of_match) and extracts the of_device_id data from the device node of the device tree. Then, shouldn't the device tree have this 'data' field in the of_device_id information somewhere?
But this is an example device tree node with 'snps,dw-pcie-ep' in the compatible field (from arch/arm/boot/dts/uniphier-pro5.dtsi).
pcie_ep: pcie-ep#66000000 {
compatible = "socionext,uniphier-pro5-pcie-ep",
"snps,dw-pcie-ep";
status = "disabled";
reg-names = "dbi", "dbi2", "link", "addr_space";
reg = <0x66000000 0x1000>, <0x66001000 0x1000>,
<0x66010000 0x10000>, <0x67000000 0x400000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pcie>;
clock-names = "gio", "link";
clocks = <&sys_clk 12>, <&sys_clk 24>;
reset-names = "gio", "link";
resets = <&sys_rst 12>, <&sys_rst 24>;
num-ib-windows = <16>;
num-ob-windows = <16>;
num-lanes = <4>;
phy-names = "pcie-phy";
phys = <&pcie_phy>;
};
It doesn't have any data field with specific 'RC' or 'EP' mode indication. Where is this 'data' field kept in the device tree??
It doesn't have any data field with specific 'RC' or 'EP' mode indication. Where is this 'data' field kept in the device tree??
The DT node doesn't have to supply such a "data" field because the "'RC' or 'EP' mode indication" is already conveyed to the device driver using the compatible property.
In the driver, there is more than one acceptable compatible string (i.e. there is more than one struct of_device_id element). Each compatible string (specified by the .compatible = ...) in the driver is also associated with a data structure (specified by the .data = ...) that specifies attributes (i.e. the mode in question) of the particular device that has to be supported.
static const struct of_device_id dw_plat_pcie_of_match[] = {
{
.compatible = "snps,dw-pcie",
.data = &dw_plat_pcie_rc_of_data,
},
{
.compatible = "snps,dw-pcie-ep",
.data = &dw_plat_pcie_ep_of_data,
},
{},
};
Since your DT node uses
compatible = "socionext,uniphier-pro5-pcie-ep",
"snps,dw-pcie-ep";
the second string in that property should be a match for the compatible string in the 2nd element of the dw_plat_pcie_of_match[] array.
So when execution returns from the
match = of_match_device(dw_plat_pcie_of_match, dev);
match should be pointing to the following structure:
{
.compatible = "snps,dw-pcie-ep",
.data = &dw_plat_pcie_ep_of_data,
},
Then the assignment
data = (struct dw_plat_pcie_of_data *)match->data;
will refer to
static const struct dw_plat_pcie_of_data dw_plat_pcie_ep_of_data = {
.mode = DW_PCIE_EP_TYPE,
};
So the assignment
mode = (enum dw_pcie_device_mode)data->mode;
will fetch the value DW_PCIE_EP_TYPE from that structure, and set the mode.
Associating a data structure with the compatible string allows a device driver to covertly support more than a single version of a device. The DT is relieved from having to specify (any and all) the distinguishing aspects of that particular version of the device. The DT node will only have properties that describe configurable or board-specific attributes.
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.
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";
};
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.