Attaching device with device driver - linux

I am trying to learn about Linux platform drivers. I have taken a driver from the following tutorial:
http://linuxseekernel.blogspot.com/2014/05/platform-device-driver-practical.html
It is a basic platform driver. I have compiled it and loaded the module. It loads fine, however, its probe function is never executed. There is a lot of documentation that has said as long as the devices id and drivers id match, then the probe function is called. Well I have the following driver:
#include <linux/module.h>
#include <linux/kernel.h>
//for platform drivers....
#include <linux/platform_device.h>
#define DRIVER_NAME "twl12xx"
MODULE_LICENSE("GPL");
/**************/
static int sample_drv_probe(struct platform_device *pdev){
printk(KERN_ALERT "twl12xx: Probed\n");
return 0;
}
static int sample_drv_remove(struct platform_device *pdev){
printk(KERN_ALERT "twl12xx: Removing twl12xx\n");
return 0;
}
static const struct platform_device_id twl12xx_id_table[] = {
{ "twl12xx", 0},
{}
};
MODULE_DEVICE_TABLE(platform, twl12xx_id_table);
static struct platform_driver sample_pldriver = {
.probe = sample_drv_probe,
.remove = sample_drv_remove,
.driver = {
.name = DRIVER_NAME,
},
};
/**************/
int ourinitmodule(void)
{
printk(KERN_ALERT "\n Welcome to twl12xx driver.... \n");
/* Registering with Kernel */
platform_driver_register(&sample_pldriver);
return 0;
}
void ourcleanupmodule(void)
{
printk(KERN_ALERT "\n Thanks....Exiting twl12xx driver... \n");
/* Unregistering from Kernel */
platform_driver_unregister(&sample_pldriver);
return;
}
module_init(ourinitmodule);
module_exit(ourcleanupmodule);
I also have the following entry in my device tree:
twl12xx: twl12xx#2 {
compatible = "twl12xx";
};
I feel like I am must be missing something or incorrectly defining my device tree.

Whatever you have read is correct; driver and device ID both should match.
You have just create the skeleton of driver and you are using the device tree. So it looks fine. But you are missing the of_match_table entry in your code; which is very important for device ID match (same string as you have pass from the device tree) and driver probe calling.
So add the below changes your code:
#ifdef CONFIG_OF
static const struct of_device_id twl12xx_dt_ids[] = {
.compatible = "ti,twl12xx",
{}
};
MODULE_DEVICE_TABLE(of, twl12xx_dt_ids);
#endif
static struct platform_driver sample_pldriver = {
.probe = sample_drv_probe,
.remove = sample_drv_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = of_match_ptr(twl12xx_dt_ids),
},
.id_table = twl12xx_id_table,
};

I had similar problem. Probe function also wasn't able to print anything. The reason in my case was: In my linux I had ready driver that was binded to the device . When I unbinded this driver, Probe function worked successfully.
(Note, to unbind:
cd /sys/bus/platform/drivers/<driver_name>
echo "device_name" > unbind
)

Related

Kernel driver combining a platform_driver with a i2c_driver

I am writing a kernel driver for a LCD. This LCD uses eight GPIO lines (d0...d7) to send data to display, some gpio control signals (on/off, enable backlight, and r/w) and a potentiometer to control the display contrast, connected to I2C bus.
I wrote a platform_driver that uses "probe" and "remove" callbacks to register/unregister a misc device that creates a /dev/lcd character device with can be used from userspace to send a buffer to be printed on the screen. I am able to read GPIOS properly defined on the DTS and also to manage those GPIOS to print strings on the LCD. This is the skeleton:
#define MODULE_NAME "lcd"
static void lcd_hw_setup(void)
{ ... }
static int lcd_open(struct inode *inode, struct file *file)
{ ... }
static ssize_t lcd_write (struct file *file, const char *buf, size_t count, loff_t *ppos)
{ ... }
static int lcd_close(struct inode *inode, struct file *file)
{ ... }
/* declare & initialize file_operations structure */
static const struct file_operations lcd_dev_fops = {
.owner = THIS_MODULE,
.open = lcd_open,
.write = lcd_write,
.release = lcd_close
};
/* declare & initialize miscdevice structure */
static struct miscdevice lcd_misc = {
.minor = MISC_DYNAMIC_MINOR, /* major = 10 assigned by the misc framework */
.name = MODULE_NAME, /* /dev/lcd */
.fops = &lcd_dev_fops,
};
static int lcd_probe(struct platform_device *pdev)
{
struct device *dev;
pr_info(MODULE_NAME ": lcd_probe init\n");
/* Register the misc device with the kernel */
misc_register(&lcd_misc);
dev = &pdev->dev;
/* gpiod_get calls to get gpios from DTS */
lcd_hw_setup();
pr_info(MODULE_NAME ": lcd_probe ok\n");
return 0;
}
static int lcd_remove(struct platform_device *pdev)
{
pr_info(MODULE_NAME ": lcd_remove\n");
/* Release gpio resources */
...
/* Unregister the device with the kernel */
misc_deregister(&lcd_misc);
return 0;
}
/* declare a list of devices supported by this driver */
static const struct of_device_id lcd_of_ids[] = {
{ .compatible = "my-lcd" },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, lcd_of_ids);
/* declare & initialize platform_driver structure */
static struct platform_driver lcd_pdrv = {
.probe = lcd_probe,
.remove = lcd_remove,
.driver = {
.name = "my-lcd", /* match with compatible */
.of_match_table = lcd_of_ids,
.owner = THIS_MODULE,
},
};
/* register platform driver */
module_platform_driver(lcd_pdrv);
That works really fine.
Now I need to send to the I2C potentiometer a initialization value to set the display contrast. That requires calling i2c_smbus_write_byte_data. I need access to a i2c_client struct for that.
I found some I2C examples that create a i2c_driver which provides probe and remove callbacks, and receive a pointer to that i2c_client struct in the probe function. But I don't find a way to relate that i2c_driver with my platform_driver. They seem to be completely independent drivers.
My questions:
Can a platform_driver and a i2c_driver be combined in a single kernel module? I mean, can I add a module_platform_driver and module_i2c_driver calls in a single kernel module?
Or maybe I have to create a second driver just to control the I2C potentiometer. In this particular case there is a dependency between both kernel modules. How that dependency should be managed?
Please some help with this would be really helpful. Thanks a lot!
As an initial work around I have developed a second driver (an i2c_driver) just to call the i2c_smbus_write_byte_data function from the probe callback. It works, but I would like to know if this is the proper way to fix this issue. Thanks!

i2c kernel driver - Binding between sysfs kobject and i2c_client

I am working on an I2C kernel driver and would like to provide a sysfs file interface in a new folder - /sys/devices/MySensor. However, when I do this I don't know how to associate the i2c client with the new kobject.
Consequently, when my device attribute functions are called, the device object passed in does not allow me to retrieve the registered i2c client.
I declare my attribute as follows:
static ssize_t my_sensor_do_something(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client;
struct my_sensor_data *data;
int size = 0;
client = to_i2c_client(dev);
my_sensor_dbgmsg("Client Address:0x%02x\n", client->addr);
data = i2c_get_clientdata(client);
return 0
}
static DEVICE_ATTR(do_something, S_IRUGO, my_sensor_do_something, NULL);
static struct attribute *my_sensor_attributes[] = {
&dev_attr_do_something.attr,
NULL
};
static const struct attribute_group my_sensor_attr_group = {
.attrs = my_sensor_attributes,
};
Then, in my probe function, create my subfolder
struct device *my_dev = root_device_register("my_sensor");
err = sysfs_create_group(&my_dev->kobj, &my_sensor_attr_group);
The sub-folder and do_something file is created in /sys/kernel/, however when do_something() is called, the attempt to retrieve the I2C client fails - client->addr is 0 and i2c_get_client_data returns null.
For info, the i2c device is defined in a device tree and I can successfully add device attributes to the existing folder
err = sysfs_create_group(client->dev.kobj, &my_sensor_attr_group);
/sys/bus/i2c/devices/i2c-7/7-004c/
Apologies if this question is vague or lacking sufficient detail. I'm relatively new to this.
Does anyone have an idea what I am missing when I create a new sysfs folder, to associate this with my registered i2c client?
Thanks
You can put the client on my_dev at initialization time.
dev_set_drvdata(my_dev, client);
Then in the my_sensor_do_something function, use dev_get_drvdata to take the client out
client = dev_get_drvdata(dev);
The complete example is as follows
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/slab.h>
static ssize_t my_sensor_do_something(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client;
void *data;
client = dev_get_drvdata(dev);
data = i2c_get_clientdata(client);
pr_info("Client Address:0x%02x Data:%p\n", client->addr, data);
return 0;
}
static DEVICE_ATTR(do_something, 0444, my_sensor_do_something, NULL);
static struct attribute *my_sensor_attributes[] = {
&dev_attr_do_something.attr,
NULL
};
static const struct attribute_group my_sensor_attr_group = {
.attrs = my_sensor_attributes,
};
static struct device *my_dev;
static void my_sensor_create(struct i2c_client *client)
{
int err;
my_dev = root_device_register("my_sensor");
dev_set_drvdata(my_dev, client);
err = sysfs_create_group(&my_dev->kobj, &my_sensor_attr_group);
if (err)
pr_info("sysfs_create_group failure.\n");
}
struct test_device {
struct i2c_client *client;
};
static int test_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct test_device *dev;
dev = kzalloc(sizeof(struct test_device), GFP_KERNEL);
if (dev == NULL)
return -ENOMEM;
dev->client = client;
i2c_set_clientdata(client, dev);
my_sensor_create(client);
return 0;
}
static int test_i2c_remove(struct i2c_client *client)
{
struct test_client *dev = i2c_get_clientdata(client);
if (my_dev)
root_device_unregister(my_dev);
kfree(dev);
return 0;
}
static const struct i2c_device_id test_i2c_id[] = {
{"test_i2c_client", 0},
{}
};
static struct i2c_driver test_i2c_driver = {
.driver = { .name = "test_i2c_client", },
.probe = test_i2c_probe,
.remove = test_i2c_remove,
.id_table = test_i2c_id,
};
static int __init test_i2c_init_driver(void)
{
return i2c_add_driver(&test_i2c_driver);
}
static void __exit test_i2c_exit_driver(void)
{
i2c_del_driver(&test_i2c_driver);
}
module_init(test_i2c_init_driver);
module_exit(test_i2c_exit_driver);
MODULE_LICENSE("GPL");

Problem with hotplugging device driver module

I'm writing a module that when you plug in a usb mouse prints "hello world". The problem comes when I plug in the mouse, dmesg prints six times the below message:
[ 7367.238560] helwor_mod: disagrees about version of symbol
module_layout
This is my code
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/usb.h>
#include <linux/usb/input.h>
#include <linux/hid.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Isaac Lleida <isakyllr#opmbx.org>");
MODULE_VERSION("0.1");
static struct usb_device_id usb_mouse_id_table [] = {
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE) },
{ }
};
MODULE_DEVICE_TABLE(usb, usb_mouse_id_table);
static int mouse_probe(struct usb_interface *iface,
const struct usb_device_id *id)
{
pr_info("Hello World!");
return 0;
}
static void mouse_disconnect(struct usb_interface *iface)
{
pr_info("Bye World!");
}
static struct usb_driver mouse_driver = {
.name = "usbmouse",
.probe = mouse_probe,
.disconnect = mouse_disconnect,
.id_table = usb_mouse_id_table,
};
module_usb_driver(mouse_driver);
static int __init hello_init(void)
{
int res = 0;
res = usb_register(&mouse_driver);
if(res)
pr_err("usb_register failed with error %d", res);
return res;
}
static void __exit hello_exit(void)
{
pr_debug("USB Mouse Removed...");
usb_deregister(&mouse_driver);
}
I have been googling all the afternoon and still don't know how to solve it.
I hope someone can help me, thanks.
This is related:
module_layout version incompatibility
I'd bet that the kernel sources (headers) you're using to compile your module are from a different kernel version than then one you're running.
Problem solved. This issue is produced because the device is being controled by another driver and it's loaded in the system. Just unload it and load your driver module.
And sorry Gilles for the offtopic.

I2C device driver error [TCA6408 I/O expander]

I want to connect TCA6408 IO Expander and get key input to my embedded system.
I am trying with SABRELite (iMX6Q) Boad and my development environment is LTIB (L3.0.35_4.1.0_130816_source.tar.gz)
I have done below modifications
1.) add an entry into "board-mx6q_sabrelite.c"
static struct i2c_board_info mxc_i2c2_board_info[] __initdata = {
{
I2C_BOARD_INFO("pca953x", 0x21),
.irq = gpio_to_irq(MX6Q_SABRELITE_CAP_TCH_INT1),
},
};
2.) Enable driver from menuconfig
--- GPIO Support
< * > PCA953x, PCA955x, TCA64xx, and MAX7310 I/O ports
[ * ] Interrupt controller support for PCA953x
When I boot the system, driver registration is OK.
But there is an error(pca953x: probe of 2-0020 failed with error -22) in Probe() function.
#Console Log
Freescale USB OTG Driver loaded, $Revision: 1.55 $
pca953x: probe of 2-0020 failed with error -22
imx-ipuv3 imx-ipuv3.0: IPU DMFC NORMAL mode: 1(0~1), 5B(4,5), 5F(6,7)
imx-ipuv3 imx-ipuv3.1: IPU DMFC NORMAL mode: 1(0~1), 5B(4,5), 5F(6,7)
mxc_mipi_csi2 mxc_mipi_csi2: i.MX MIPI CSI2 driver probed
mxc_mipi_csi2 mxc_mipi_csi2: i.MX MIPI CSI2 dphy version is 0x3130302a
MIPI CSI2 driver module loaded
Advanced Linux Sound Architecture Driver Version 1.0.24.
This error occured becauseof (pdata == NULL)
linux-3.0.35/drivers/gpio/pca953x.c
static int __devinit pca953x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pca953x_platform_data *pdata;
struct pca953x_chip *chip;
int ret = 0;
chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
pdata = client->dev.platform_data;
if (pdata == NULL) {
pdata = pca953x_get_alt_pdata(client);
/*
* Unlike normal platform_data, this is allocated
* dynamically and must be freed in the driver
*/
chip->dyn_pdata = pdata;
}
if (pdata == NULL) {
dev_dbg(&client->dev, "no platform data\n");
ret = -EINVAL;
goto out_failed;
}
I can not understand the problem. what kind of modification needs in "platform_data"?
anybody please support me.
You need to supply some platform data in the i2c_board_info structure.
From the code you supplied, the structure should be of type struct pca953x_platform_data and
referred to in the platform_data field.
i.e. (SABRE Lite Board)
static struct pca953x_platform_data my_pca953x_pdata = {
.gpio_base = MX6Q_PAD_GPIO_5__I2C3_SCL,
};
static struct i2c_board_info mxc_i2c2_board_info[] __initdata = {
{
I2C_BOARD_INFO("pca953x", 0x21),
.irq = gpio_to_irq(MX6Q_SABRELITE_CAP_TCH_INT1),
.platform_data = &my_pca953x_pdata
},
};
Here is an example for am3517 board and tca6416. platform_data specifies from what GPIO number new GPIO should be counted. For example OMAP_MAX_GPIO_LINES 128, then the first tca6416 GPIO would be 128 + 1 = 129.
static struct pca953x_platform_data sp860_gpio_expander_info_0 = {
.gpio_base = OMAP_MAX_GPIO_LINES,
};
static struct i2c_board_info __initdata am3517evm_i2c2_boardinfo[] = {
{
I2C_BOARD_INFO("tca6416", 0x20),
.platform_data = &sp860_gpio_expander_info_0,
},
};
You can set following parameters in this platform_data structure:
struct pca953x_platform_data {
/* number of the first GPIO */
unsigned gpio_base;
/* initial polarity inversion setting */
uint16_t invert;
/* interrupt base */
int irq_base;
void *context; /* param to setup/teardown */
int (*setup)(struct i2c_client *client,
unsigned gpio, unsigned ngpio,
void *context);
int (*teardown)(struct i2c_client *client,
unsigned gpio, unsigned ngpio,
void *context);
const char *const *names;
};

"Device has no release() function" - what does this mean?

I am trying to write a simple linux kernel driver to turn a GPIO pin on while the module is loaded. Module loading works, but when I call rmmod to remove it I get this error:
sudo rmmod psctl
[13051.599199] ------------[ cut here ]------------
[13051.608758] WARNING: at drivers/base/core.c:196 device_release+0x78/0x84()
[13051.620581] Device 'psctl.0' does not have a release() function, it is broken and must be fixed.
[13051.637898] Modules linked in: psctl(O-) tmp102 hwmon nfsd rtc_ds1307 i2c_dev snd_bcm2835 snd_pcm snd_page_alloc snd_seq snd_seq_device snd_timer snd spidev leds_gpio led_class spi_bcm2708 i2c_bcm2708 [last unloaded: psctl]
[13051.670268] [<c0013f64>] (unwind_backtrace+0x0/0xf0) from [<c001e80c>] (warn_slowpath_common+0x4c/0x64)
[13051.688743] [<c001e80c>] (warn_slowpath_common+0x4c/0x64) from [<c001e8b8>] (warn_slowpath_fmt+0x30/0x40)
[13051.707217] [<c001e8b8>] (warn_slowpath_fmt+0x30/0x40) from [<c0239240>] (device_release+0x78/0x84)
[13051.725132] [<c0239240>] (device_release+0x78/0x84) from [<c01f4ad8>] (kobject_release+0x50/0x84)
[13051.742880] [<c01f4ad8>] (kobject_release+0x50/0x84) from [<bf0e6064>] (gpiotest_exit+0x10/0x2c [psctl])
[13051.761326] [<bf0e6064>] (gpiotest_exit+0x10/0x2c [psctl]) from [<c005e140>] (sys_delete_module+0x1b4/0x240)
[13051.780050] [<c005e140>] (sys_delete_module+0x1b4/0x240) from [<c000dae0>] (ret_fast_syscall+0x0/0x30)
[13051.798205] ---[ end trace 2eaa6df2dbf1f2e2 ]---
[13051.810083] psctl: Unloaded module
What does this mean? I have had a look at drivers/base/core.c and it seems that neither the kobject or the kobj_type have a release method associated with them (or there is no kobj_type set on the kobj). Am I supposed to set the release method myself, or is there something else that I haven't done that would set this for me?
The code for the module is below:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#define AUTHOR "Xian Stannard <xian#xianic.net>"
#define DESCRIPTION "Simple GPIO driver as proof of concept"
#define VERSION "0.1"
#define DRIVER_NAME "psctl"
#define OUT_GPIO 18
#define MPRINT(level, fmt, args...) printk(level DRIVER_NAME ": " fmt "\n", ## args)
struct ps_data_struct {
int out_gpio;
};
static int ps_probe(struct platform_device *pdev) {
struct ps_data_struct *data = pdev->dev.platform_data;
if(data == NULL)
MPRINT(KERN_DEBUG, "No platform data");
else {
MPRINT(KERN_DEBUG, "Has platform data: gpio %d", data->out_gpio);
}
return -ENODEV;
}
static int __exit ps_remove(struct platform_device *dev) {
MPRINT(KERN_DEBUG, "Remove");
return 0;
}
static void ps_release(struct device* dev) {
MPRINT(KERN_DEBUG, "Release");
}
static struct ps_data_struct ps_data = {
.out_gpio = OUT_GPIO
};
static struct platform_driver ps_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE
},
.probe = ps_probe,
.remove = __exit_p(ps_remove)
};
static struct platform_device ps_device = {
.name = DRIVER_NAME,
.id = 0,
.dev = {
.platform_data = &ps_data
}
};
static int __init gpiotest_init(void) {
int retval = 0;
retval = platform_driver_register(&ps_driver);
if(retval != 0) {
MPRINT(KERN_ERR, "Could not register driver");
goto drvreg;
}
retval = platform_device_register(&ps_device);
if(retval != 0) {
MPRINT(KERN_ERR, "Could not create device");
goto devreg;
}
MPRINT(KERN_INFO, "Loaded module");
return 0;
devreg:
platform_driver_unregister(&ps_driver);
drvreg:
MPRINT(KERN_ERR, "Module load failed with error code %d", retval);
return retval;
}
static void __exit gpiotest_exit(void) {
platform_device_unregister(&ps_device);
platform_driver_unregister(&ps_driver);
MPRINT(KERN_INFO, "Unloaded module");
}
module_init(gpiotest_init);
module_exit(gpiotest_exit);
MODULE_AUTHOR(AUTHOR);
MODULE_DESCRIPTION(DESCRIPTION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
I think using platform_device_register() to register a device, the pdev->dev->release is not initialized, so when you try to remove this device, the OOPS message print out.
There are two solutions to solve this problem:
Using platform_device_alloc() and platform_device_add() to register your device;
You init the ps_device.dev.release yourself, if you insist on using platform_device_register().
When you call platform_device_alloc() to get an instance of device, the release method initialization is done to the default function, as can be see here.
struct platform_device *platform_device_alloc(const char *name, int id)
{
...
...
pa->pdev.dev.release = platform_device_release;
...
...
}
This is the default implementation of platform_device_release .
However, when you avoid platform_device_alloc, you obviously miss this initialization and hence need to provide your own implementation of release method for device.

Resources