9

How to make a character device for i2c device, with open, close, ioctl etc. functions? I was looking for information about it last two weeks and couldn't find anything working. I found some information in Essential Linux Device Drivers, but it was written for 2.6 kernel, and i use 3.4.79 (i'm trying to write this driver for cubieboard2 on cubian distr) so this book has many deprecated functions, i tried to write my driver like there, but it still don't work (give me kernel errors while i'm truing to cat character device). Can anyone explain me what to do with it, or at least give me a working example.

so, there is my code: http://pastebin.com/T7PBTpym

i just try to get i2c bus works, but on my oscilloscope i don't see anything on i2c lines, while i get no errors when i compile it. Also i can't find how to attach device driver to i2c bus number. because i have 4 i2c buses on my cubieboard2, and how to attach device driver to i2c-1 bus, for example?

mishaskt
  • 241
  • 1
  • 2
  • 9
  • You probably don't need to write your own kernel driver from scratch for i2c; the kernel these days provides i2c as a subsystem that is likely well supported for something like the cubieboard2, which uses the Allwinner SOC, (although I stand to be corrected!) Have you done a search for other usage examples? It will probably be more a matter of working out how to turn it on, then accessing it from userspace... – 6EQUJ5 Jun 01 '14 at 11:44
  • 1
    Depending on the hardware you may need to add pullup resistors on the i2c lines – 6EQUJ5 Jun 01 '14 at 11:45
  • The linux source is copy-left, so you could download the linux source (it is free), then find the existing I2C driver and see how it is done. Perhaps simply modify the config file and re-compile/configure/install the linux OS. – user3629249 Jun 01 '14 at 17:50
  • 1) if your i2c client device is using low load and single client, then go for i2c-gpio. don't struggle with i2c host controllers. 2) Please download open source kernel and refer /drivers/misc/fsa9480.c(it uses i2c-gpio driver.) – kzs Jun 01 '14 at 18:38

1 Answers1

15

Thank you, guys. I've found what I want a couple hours ago. So as I see there are three types of drivers. One is supposed to be inserted into the kernel, and you need to rebuild your kernel to use them. There are also drivers that you can use through the sysfs using device attributes (they appear in /sys/bus/i2c/driver/your_driver/). And, third - my type - drivers that look like character devices. Actually, you can combine them.

So, if you want to use last type of devices it'll be a bit difficult to find correct examples, because almost all examples are devoted to the first two types of drivers. Anyway, if you want to create a character device, you need to describe functions from the file_operations structure. But all functions like i2c_transfer, i2c_smbus_read_byte. Etc. (full list) required eitherstruct i2c_adapter or struct i2c_client. And there two questions, how to get there structures, and how to attach driver to the appropriate i2c bus, such as i2c-2?

So there is a function that is not described here: i2c_get_adapter. As a parameter, you need to pass the i2c bus number. It returns a link to a i2c_adapter structure. The i2c_client structure you can get with i2c_new_dummy function passing i2c_adapter and slave address to it as parameters.

After that you can use functions such as i2c_transfer, i2c_smbus_read_byte etc. In the end you can describe file_operations structure functions, and release driver, representing your i2c device, without using sysfs and rebuilding your kernel.

Result code looks like:

u8 ret; 
struct i2c_client * my_client; 
struct i2c_adapter * my_adap = i2c_get_adapter(1); // 1 means i2c-1 bus
my_client = i2c_new_dummy (my_adap, 0x69); // 0x69 - slave address on i2c bus
i2c_smbus_write_byte(my_client, 0x0f); 
ret = i2c_smbus_read_byte(my_client);

You can use this code directly in your functions for the file_operations structure.

Hope this info will be useful for beginners like me.

elixenide
  • 44,308
  • 16
  • 74
  • 100
mishaskt
  • 241
  • 1
  • 2
  • 9
  • Is the slave address (in your example, 0x69) the address we assign to the i2c driver of computer to act in slave mode? I would like to use the i2c of my SoC module in slave mode but the kernel (3.14.77) doesn't support it. – Rasoul Nov 16 '16 at 14:29
  • This is not the way to do it. Look at any driver that defines `struct i2c_driver` for the answer. You define a `.probe` method and give a name or list of names. The kernel will call your probe method on any I2C device that matches your name(s). The probe method looks like `my_probe(struct i2c_client *client, const struct i2c_device_id *id)` As you can see, the i2c_client is already there to use. You don't create a dummy one at a hard-coded bus and address. – TrentP Jan 22 '17 at 18:53
  • Agreed with TrentP. I wrote up an explanation of my solution for a similar problem with one driver accessing multiple slaves. Here:: http://stackoverflow.com/questions/39370398/how-to-write-multiple-slave-i2c-client-device-driver/42235875#42235875. The idea is the same. You need to store the i2c_client somewhere, then when your driver's .open gets called, you need to put the appropriate i2c_client in filep->private_data so later read/write/ioctls can use that directly. As opposed to have to create a i2c_new_dummy(). How this answer got 8 upvotes is beyond me. – Splaty Feb 14 '17 at 21:09
  • This is actually very useful since it allows you to develop a driver that you can load on the fly; if you do it "properly" using the `probe` method, you need to modify the DTS and rebuild the kernel image. For getting a prototype off the ground iterating quickly this hits the spot - but indeed, once working, you would then initialise it properly using `probe`. – Den-Jason Sep 18 '19 at 10:09