Non-blocking i2c read from userspace - linux

I'm trying to read and write data off i2c in slave mode and have found several examples to do this in userspace including this most relevant one from NXP (I'm using the iMX8MQ):
https://source.codeaurora.org/external/imx/imx-test/tree/test/mxc_i2c_slave_test/mxc_i2c_slave_test.c?h=imx_4.14.78_1.0.0_ga
However, it looks like if I want to read data, it would be a polling based implementation because it looks like i2c-dev does not provide a way to register userspace callbacks when i2c data is available. Not even sure if any Linux device drivers allow doing this at all. Am I correct in assuming that there is no non-blocking and asynchronous way of doing an i2c read from userspace in slave mode?
I'm not very familiar with writing device drivers so even if I wanted to implement my own, similar to this one:
https://github.com/torvalds/linux/blob/master/drivers/i2c/i2c-slave-eeprom.c
is it a good idea to call a userspace function when data became available (for instance when the driver received an I2C_SLAVE_STOP)?

Related

Preferred Linux driver architecture for a multi-function PMU device

I have a bespoke/complex Power Management Unit which exposes its functionality as an I2C slave with 16-bit registers and an interrupt (out) signal.
This PMU also has GPIO functionality.
(The interrupt tells the Linux kernel (I2C master) to read registers because a GPIO input has changed state).
Currently, I've structured the (working) driver(s) as:
./include/linux/mfd/mypmu.h
./drivers/gpio/gpio-mypmu.c
./drivers/mfd/mypmu-core.c
./drivers/mfd/mypmu-regmap.c
./drivers/mfd/mypmu-i2c.c
I have three MODULE_DESCRIPTION() macro invocations:
./drivers/gpio/gpio-mypmu.c:MODULE_DESCRIPTION("GPIO interface for MYPMU");
./drivers/mfd/mypmu-core.c:MODULE_DESCRIPTION("MYMU device");
./drivers/mfd/mypmu-i2c.c:MODULE_DESCRIPTION("MYPMU_I2C");
The reason that it's split into three separate modules is that I use different ways of registering each module, according to the kernel subsystem of which they are a part.
./drivers/gpio/gpio-mypmu.c:platform_driver_register(&mypmu_gpio_driver);
./drivers/mfd/mypmu-core.c:platform_set_drvdata(*pdev, mypmu);
./drivers/mfd/mypmu-i2c.c:i2c_add_driver(&mypmu_i2c_driver);
(This is largely cargo-cult programming, caused by aping other (single-function) drivers' code.)
Is using three modules in one device driver normal? Or is there a way to register one driver in multiple Linux subsystems, such as GPIO and I2C?
Can a driver appear in /sys/class/gpio without a module living in the drivers/gpio tree?
Is there a better way of structuring an MFD driver?

Best Way to copy data from Kernel Driver to user space driver

I am having a kernel driver which is currently reading data from a sensor.
Now I have to write a user space application which will call kernel's sensor_read() API and send data to cloud.
How can I expose kernel's sensor_read() call to user space and read this data from user space? Data is about 10 bytes.
How can I expose kernel's sensor_read() call to user space and read this data from user space?
Most likely you should use IIO kernel framework, as it's specifically designed for writing sensor drivers. IIO exposes necessary files for your driver (in /sys/bus/iio/ and /dev/iio*). You can read() those files, or poll() them (to handle interrupts).
Official documentation is available here. You can also use some existing drivers as a reference, look here: drivers/iio/ .
Before IIO framework was introduced, it was common to provide sysfs files for drivers manually. So if you use old enough kernel, that should be the way to write the driver: handle your bus (like I2C) and sysfs files manually. But still, the best way is to use new kernel and IIO.
I am working on a Gyro + accel sensor. Linux driver will be sending events of type EV_MSC for both of them
It's not unusual for chip to have more than one sensor on it. In that case you should create two different drivers: one for accelerometer, and one for gyro. This way you will have two different files, one file per sensor.
For example, look how it's done for LSM330DLC chip (accelerometer + gyro):
accel driver: drivers/iio/accel/st_accel_core.c
gyro driver: drivers/iio/gyro/st_gyro_core.c
Both drivers are calling iio_device_register() function from driver's probe function, which creates corresponding files (which you can read/poll). Refer to documentation for further details.
As per my understanding I will open both the input devices from user space and add then to list of FD's which we want to poll. So when there is a new event how I can determine whether this event is from Gyro or aceel?
If you are curious about how to handle two /dev/input/event* files in user space, you basically have two choices:
using blocking I/O: you can read/poll them in different threads
using non-blocking I/O: you can open those files as O_NONBLOCK and just read() them in the same one thread; if new data is not available yet -- it will return -1 and errno will be set to EAGAIN; you can do those reads in infinite loop, for instance
This answer contains example of how to handle input file in C. And here you can read about blocking/non-blocking I/O.
There are many ways to access sensors data from kernel space to userspace
Check for relevant driver of the sensor you used. Check whether it supports/provides sysfs support.
you can read the data from /sys/class/ interfaces. You need to ensure that the relevant parameters exported to sysfs.
For eg: Temperature sensors should have exported temperature values(equivalent factors) in sysfs entry.
Examples(Below examples are fictions only)
cat /sys/class/hwmon/tempsensor/value
cat /sys/class/hwmon/tempsensor/min_value
cat /sys/class/hwmon/tempsensor/max_value
In some drivers, you can read them through ioctl / read / write api's to read/write sensor data.
You can use IOCTL (ioctl/read) calls to access the kernel functions from User space.
Refer below link for sample:
http://www.tldp.org/LDP/lkmpg/2.4/html/x856.html

Linux: access i2c device within board_init function

(iMX6 SOC running Linux 3.0)
I need to run a few I2C transactions in my board_init function. I tried calling i2c_get_adapter, then i2c_transfer, those being available in kernel mode, but i2c_get_adapter returns NULL. It's already called imx6q_add_imx_i2c, which is a wrapper around platform_device_register_full, but that isn't enough.
I can manipulate GPIO in board_init by calling gpio_request to obtain access, and gpio_free at the end. Is there something analogous to those functions for i2c?
--- added details ---
I've got a LAN9500A USB 100Base-T Ethernet MAC connected to a LAN9303 3-port switch with a virtual PHY. The MAC has a GPIO reset line that has to be turned off before it will spring to life and enumerate on the USB. That's done in board_init because it's completely nonstandard, so we don't want to patch the stock driver to manipulate some GPIO that's not part of the device.
The problem I'm having is that even though the MAC is permanently attached to the VPHY, it's not noticing it's connected, and an "ip link show eth1" command shows NO-CARRIER. I found I can kickstart it by unmasking the VPHY's Device Ready interrupt via I2C, but I also have to mask it immediately, or I get infinite interrupts. That's not the right solution, but Microchip has been no help in showing me a better way. But we don't want to patch the MAC driver with code to fiddle with the PHY.
There is no PHY driver for this part, and the MII interface to the VPHY doesn't include any interrupt-related registers, so it must be done through I2C. Writing a PHY driver just to flip a bit on and off once seems a lot of trouble, especially for a newbie like me who's never written a driver before.
I can do it in Python in a startup script, but that, too, seems like a heavyweight solution to a lightweight problem.
That's a wrong approach. Board file supposed to register device drivers and pass important information to them, rather than act as a device driver itself. I'm not sure if what you're trying to do is even possible.
If you really need to extract something from your I2C device on a very early stage - do that in the bootloader and pass the data to kernel via cmdline (U-boot, by the way, has I2C support for a quite some time). Then later, kernel might do appropriate actions depending on what you have passed to it.

How a device driver recognise the peripheral mapping in embedded unix

In most example project for embedded system there is a system file in which we can find structures for different peripheral as well as the memory mapping of the peripheral register, in addition there is also a module per peripheral that contains basic function to manipulate the periheral like: periph_enable, periph_write, periph_read; this is the architecture i have in mind when i tackle a new project.
Actually i started to work with a BF609 but now with an embedded linux in it, my task consist in writing a communication driver with another device via UART, as usual i tried to look for the files i used to use but in vain, i can't find the mapping of the different peripheral.
I started to read this book, i undrestand that the kernel see each device like a file and that a driver is mainly the implementation of the open, close, read and writefunctions in these file but i still don't undrestand how these functions communicate with peripheral registers.
My questions:
1) How device drivers recognise the mapping of the peripheral is there sth i missed, is there any example that explain how to implement simple read and write functions via UART for example
2) Where can i find the mapping of the peripheral in the buildroot directory
Thanks in advance

Transfer data from linux to fpga and inversely?

I have booted a ubuntu on a ZedBoard. I want to transfer data between fpga and linux. For example, I want to write or read a register from linux. What is best way for doing it? I have not any idea.
Thanx.
First of all, you need to specifically say what you want to do, for example. if you want to access the IO signals on the FPGA, you need to first add the GPIO module to your system, synthesize and implement it.
Then you use the Linux GPIO Driver to access the port as it is explained in this page:
Linux GPIO Driver
The GPIO driver fits in the Linux GPIO framework which is not a char
mode driver. Yet it does provide access to the GPIO by user space
through the sysfs filesystem. This allows each GPIO signal to be read
and written in similar manner to a char mode device. The interface is
somewhat documented in the kernel tree at Documentation/gpio.txt. The
following text is aimed to augment, not replace the existing
documentation.
For other, more complex interfaces you need to create your own driver or use one of the drivers that are available and modify it to fit your needs.

Resources