How to use gpio from device tree in a i2c_driver? - linux-kernel

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.

Related

How is the 'data' field provided by the device tree (for platform devce case)?

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.

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.

probe is not getting called in i2c driver

I am trying to learn to write a i2c driver on raspberry pi board and i have taken groove LCD back-light.Here driver.probe is not getting called whereas driver's inserted in system as i can see in dmesg.
Init code of driver is getting called, and code =>
static int lcd_probe(struct i2c_client *i2c_client, const struct i2c_device_id *i2c_id)
{
int ret = 0;
//struct lcd_data *lcd_data;
// struct device *dev = &i2c_client->dev;
// lcd_data->client = i2c_client;
pr_debug("lcd_probe : calling the probe\n");
pr_debug("lcd_probe : i2c_client->addr = %d, i2c_client_name = %s\n",
i2c_client->addr, i2c_client->name);
return ret;
}
static struct i2c_device_id lcd_id[] = {
{"lcd", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, lcd_id);
static struct i2c_driver lcd_driver = {
.driver = {
.name = "lcd",
.owner = THIS_MODULE,
},
.probe = lcd_probe,
// .remove = lcd_remove,
// .attach_adapter = lcd_attach,
.detect = lcd_detect,
.id_table = lcd_id,
};
static int __init lcd_init(void)
{
pr_debug("lcd_init : calling init\n");
return (i2c_add_driver(&lcd_driver));
}
and dmesg =>
[ 1.971009] lcd_init : calling init
But driver.probe is not registering in i2c subsystem.
board file initialization =>
Board init code =>
/** start aartyaa lcd i2c driver */
printk(KERN_INFO "board file registering i2c lcd device\n");
i2c_register_board_info_dt(1, lcd_i2c_devices, ARRAY_SIZE(lcd_i2c_devices));
i2c_board_info code =>
/** aaryaa i2c lcd struct */
static struct i2c_board_info __initdata lcd_i2c_devices[] = {
{
.type = "lcd",
.addr = 0x62,
},
};
i added debugs in i2c_register_device
and i found driver prove device is not getting called. dmesg i have linked
dmesg link
It seems that i need to register in platform also ..
How probe gets called in i2c ... ?
Any help will be appreciated.
Thank you...!!!

Associate existing Linux device structure with device file

I'm developing with a PowerPC 405 embedded in a Virtex4 FPGA with Linux kernel 2.6.33.
Up until now, I've been writing drivers for platform devices implemented in the FPGA in the form of kernel loadable modules. The devices are registered using the flat Open Firmware Device Tree file. To create a device file, I use the OF functions to get the device node, and then register a new miscdevice which then automatically registers a minor device number and creates the device file for me. This also creates a device that is embedded in the miscdevice (i.e. miscdevice.this_device)
The problem is now I need to perform DMA operations. I tried to call the dma_alloc_coherent() function using the miscdevice.this_device, but this device isn't associated with any bus and always returns an error. I did some digging around and it turns out that the struct of_device also has a struct device embedded in it (i.e. of_device.dev). When I tried using this with dma_alloc_coherent(), it worked just fine.
So now I have two different struct device structures, one to manage my character device file, and one to manage the underlying Open Firmware system calls, the bus and DMA transactions. These devices are not associated with each other in the sysfs of course.
My question is, is it possible to somehow request that a device file be created for the device structure I get from the OF layer and not create a new device with the Misc Device API? That way everything will be associated with a single device structure.
I think your fix about dma_alloc_coherent() is correct.
But I don't think it's not right to use the device structure embedded in structure of_device to replace the miscdevice you created. The of_device is description of objects in Open Firmware database. And according to Linux device driver model, device structure is embedded in various device objects in Linux Kernel. And I think you registe miscdevice as one character device, there should be file_operations structure associated.
In one word, they are different views, and they can not replace each other.
I wrote some experimental dma driver using miscdevice.this_device for raspberry pi
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/miscdevice.h>
#include "gpio.h"
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include "DMA.h"
#include <linux/of_irq.h>
static int my_open(struct inode *i, struct file *f)
{
printk(KERN_INFO "Driver: open() %d\n", current->pid);
return 0;
}
static int my_close(struct inode *i, struct file *f)
{
printk(KERN_INFO "Driver: close()\n");
return 0;
}
static ssize_t my_read(struct file *f, char __user *buf, size_t len, loff_t *off)
{
printk(KERN_INFO "Driver: read()\n");
return 0;
}
char databuf[100];
static ssize_t my_write(struct file *f, const char __user *buf, size_t len, loff_t *off)
{
if(copy_from_user(databuf, buf, 100) != 0) return 0;
printk("Data from the user: %s\n", databuf);
return len;
}
static struct file_operations sample_fops =
{
.owner = THIS_MODULE,
.open = my_open,
.release = my_close,
.read = my_read,
.write = my_write
};
struct miscdevice sample_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "ledButton",
.fops = &sample_fops,
.mode = 0666,
};
//static struct dmadata_s *cpu_addr;
//dma_addr_t dma_addr;
struct dma_cb *virt_cb;
dma_addr_t phys_cb;
uint32_t *virt_src;
dma_addr_t phys_src;
uint32_t *virt_dst;
dma_addr_t phys_dst;
static irqreturn_t dma_irq_fn(int irq, void *dev_id)
{
printk("destAddr %u\n", *virt_dst);
dma_regs->CS.INT = 1;
return IRQ_HANDLED;
}
static struct device *dev;
int IRQ_DMA0;
static int __init ofcd_init(void) /* Constructor */
{
int error, mret;
struct device_node * np = NULL;
error = misc_register(&sample_device);
if (error) {
pr_err("can't misc_register :(\n");
return error;
}
dev = sample_device.this_device;
dev->coherent_dma_mask = ~0;
dev->dma_mask = &dev->coherent_dma_mask;
// dev_set_name(dev, "mydmadev");
// cpu_addr = (struct dmadata_s*)kmalloc(sizeof(struct dmadata_s), GFP_KERNEL | GFP_DMA);
//dma_addr = dma_map_single(dev, cpu_addr, sizeof(struct dmadata_s), DMA_BIDIRECTIONAL);
virt_cb = dma_alloc_coherent(dev, 32, &phys_cb, GFP_KERNEL | GFP_DMA);
if(virt_cb == 0 || phys_cb == 0){
printk("DMA cb error\n");
}
virt_src = dma_alloc_coherent(dev, 4, &phys_src, GFP_KERNEL | GFP_DMA);
if(virt_src == 0 || phys_src == 0){
printk("DMA src error\n");
}
virt_dst = dma_alloc_coherent(dev, 4, &phys_dst, GFP_KERNEL | GFP_DMA);
if(virt_dst == 0 || phys_dst == 0){
printk("DMA dst error\n");
}
memset(virt_cb, 0, sizeof(*virt_cb));
dma_regs = (struct dma_ch *)ioremap(DMA_BASE, sizeof(struct dma_ch));
// strcpy(cpu_addr->srcAddr, "DMA0");
*virt_src = 200;
virt_cb->TI.SRC_INC = 1;
virt_cb->TI.DEST_INC = 1;
virt_cb->TI.INTEN = 1;
virt_cb->SOURCE_AD = (uint32_t)phys_src;
virt_cb->DEST_AD = (uint32_t)phys_dst;
virt_cb->TXFR_LEN = 4;
virt_cb->reserved[0] = 0;
virt_cb->reserved[1] = 0;
printk("srcAddr %u\n", *virt_src);
printk("destAddr %u\n", *virt_dst);
//dma_regs->CS = (DMA_CS_t){.RESET = 1, .END = 1};
dma_regs->CS.RESET = 1;
udelay(10);
// dma_regs->CS = (DMA_CS_t){.END = 1, .INT = 1};
dma_regs->CS.INT = 1;
dma_regs->CS.END = 1;
dma_regs->CONBLK_AD = (uint32_t)phys_cb;
//dma_regs->DEBUG = (DMA_DEBUG_t){.READ_LAST_NOT_SET_ERROR = 1, .FIFO_ERROR = 1, .READ_ERROR = 1};
dma_regs->DEBUG.READ_LAST_NOT_SET_ERROR = 1;
dma_regs->DEBUG.FIFO_ERROR = 1;
dma_regs->DEBUG.READ_ERROR =1;
udelay(10);
// dma_regs->CS = (DMA_CS_t){.RESET = 1, .PRIORITY = 8, .PANIC_PRIORITY = 8, .ACTIVE = 1};
dma_regs->CS.RESET = 1;
udelay(10);
dma_regs->CS.PRIORITY = 8;
dma_regs->CS.PANIC_PRIORITY = 8;
dma_regs->CS.ACTIVE = 1;
if(dma_regs->CS.ERROR) printk("ERROR %d %d\n", dma_regs->CS.ACTIVE, dma_regs->CS.PANIC_PRIORITY);
//np = of_find_compatible_node(NULL,NULL,"brcm,bcm2835-system-timer");
np = of_find_node_by_path("/soc/dma#7e007000");
if (np == NULL){
printk("Error node not found\n");
}
// printk("node name %s\n", np->name);
IRQ_DMA0 = irq_of_parse_and_map(np, 0);
if (IRQ_DMA0 <= 0) {
printk("Can't parse IRQ\n");
}
mret = request_irq(IRQ_DMA0, dma_irq_fn, IRQF_SHARED, "dma", &dma_irq_fn);
if (mret < 0) printk(KERN_ALERT "%s: dma request_irg failed with %d\n", __func__, mret);
return 0;
}
static void __exit ofcd_exit(void) /* Destructor */
{
free_irq( IRQ_DMA0, &dma_irq_fn );
//dma_unmap_single(dev, dma_addr, sizeof(struct dmadata_s), DMA_BIDIRECTIONAL);
//kfree(cpu_addr);
dma_free_coherent(dev, 32, virt_cb, phys_cb);
dma_free_coherent(dev, 4, virt_src, phys_src);
dma_free_coherent(dev, 4, virt_dst, phys_dst);
iounmap(dma_regs);
// device_unregister(dev);
misc_deregister(&sample_device);
printk(KERN_INFO "Module unregistered\n");
}
module_init(ofcd_init);
module_exit(ofcd_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("MBajor>");
MODULE_DESCRIPTION("PiCNC driver");
MODULE_VERSION("0.1");
I hope this help.

Resources