Reading/writing SPI devices - linux-device-driver

(I am really unsure of which tags to apply, so apologies in advance if I chose the wrong ones.)
I hope that this is not a too stupid question, but I'm really lost here.
A client lent me an Atmel SAMA5D2 Xplained board with Linux4SAM to play around with. I'm trying to interface the SPI interface on it, but I have no clue where to start.
To be clear, I've used similar boards (not this particular one) bare-metal. I've also used Linux for many years and wrote a few simple devices drivers some years ago. And still I'm lost.
dmesg | grep spi gives me the following output:
[ 1.840000] atmel_spi f8000000.spi: version: 0x311
[ 1.840000] atmel_spi f8000000.spi: Using dma0chan0 (tx) and dma0chan1 (rx) for DMA transfers
[ 1.850000] atmel_spi f8000000.spi: Using FIFO (16 data)
[ 1.860000] atmel_spi f8000000.spi: Atmel SPI Controller at 0xf8000000 (irq 32)
[ 1.860000] m25p80 spi32766.0: at25df321a (4096 Kbytes)
From this I infer that a driver is loaded and that it is configured to use DMA. Yet, looking in /dev/ there is nothing that looks like a SPI device (I was expecting to find something like /dev/spidev or /dev/spi32766.0 or similar.)
Does this mean that there is no actual device driver loaded? Do I have to write one in order to use the SPI?
If I look at the Makefile in the Linux4SAM source tree, I see around line 1171 that the kernel does not support loading of modules. Does this imply I have to recompile the kernel to include my new driver? This seems to be a silly approach; why providing a Linux distribution if I can't access the hardware with it?
What am I missing here?
(I feel rather stupid...)
EDIT To be clear: I want to access the external SPI interface that will be connected to some external device. I think the m25p80 is some internal Flash memory; I'm not interested to read/write there.

spidev is a standard Linux device driver which just exports a low level API to userspace via /dev interface
if you want to access specific SPI client(slave) you should write your driver
according to Linux SPI driver model:
static const struct of_device_id myspi_dt_ids[] = {
{ .compatible = "xxxx,yyyyy" },
{},
static struct spi_driver xxx_spi_driver = {
.driver = {
.name = "myspi",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(myspi_dt_ids),
},
.probe = myspi_probe,
.remove = myspi_remove,
e.g. define spi_driver struct, of_device_id struct, callbacks(hooks), and register it.
You should bind it to your DT node with compatible property string.
myspi#0 {
compatible = "xxxx,yyyyy";
spi-max-frequency = <5000000>;
reg = <0>;
};
second,
compatible = "linux,spidev";
Linux discourages using this compatible property because nodes should
describe real HW devices not userspace abstractions

#0andriy put me on the right track. I had to add a SPI resource to the Device Tree and flash the compile Device Tree Blob to the board. (Since I didn't know about Device Trees at all, this information is really hard to find...).
I now have a /dev/spidev32765.0. I added this to the device tree:
spi1: spi#fc000000 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_spi1_default>;
status = "okay";
spidev#0 {
compatible = "linux,spidev";
spi-max-frequency = <83000000>;
reg = <0>;
};
};
pinctrl#fc038000 {
pinctrl_spi1_default: spi1_default {
pinmux = <PIN_PD25__SPI1_SPCK>,
<PIN_PD26__SPI1_MOSI>,
<PIN_PD27__SPI1_MISO>,
<PIN_PD28__SPI1_NPCS0>;
bias-disable;
};
};
Although I read that adding the spidev#0 is not really the right thing to do (I indeed see in dmesg output "spidev spi32765.0: buggy DT: spidev listed directly in DT").
Now, if I run spidev_test it still doesn't work (it times out), but I guess that's for another question.

Related

How to - device tree node for platform/miscdevice

I am trying to create a very basic platform/miscdevice driver for the beaglebone black, but cannot get the device tree to compile when adding the corresponding node.
(I am trying to get the bare minimum working here. Will add more information to the node once I have got the basics working, and can probe successfully)
I have been following this guide (among others):
https://elinux.org/BeagleBone_and_the_3.8_Kernel
I am trying to add the device node to the OCP part of the device tree, as instructed on several guides I have found.
This is for beaglebone black - example shown from my addition to am33xx.dtsi:
ocp {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;
ti,hwmods = "l3_main";
/* MY ADDITION *****************/
beep {
compatible = "my-beep"
};
/*******************************/
..... (other nodes)
};
I have tried adding this node to am33xx.dtsi, am335x-bone-common.dtsi and building with buildroot.
And have also tried adding the node to am335x-boneblack.dts, then trying to manually make the dtb.
Neither method will compile the device tree binary (it is saying there is error)
I am fairly sure the entry should be in am33xx.dtsi however.
Can anyone guide how a very basic platform/miscdevice node entry should be structured correctly? Should it even be in ocp?
Ian, that was a typo in the code above, however you were correct - I was missing a semicolon in another part. Very basic and embarrassing. A lesson to be more careful with this in device tree...
Sawdust, thanks I will investigate this further.

STM32 - Cortex M3: STIR register

I'm trying to write code in order to generate software trigger. Datasheets seem confusing to me and I cannot find any example on NET.
In the "Cortex-M3 devices Generic User Guide" in 4.2.8 I read to write in NVIC->STIR register to generate a software interrupt:
[STIR register][1]
But, if I understood correctly USERSETMPEND must be set to 1 for unprivileged software (I think it's my case).
But If I want to access to SCR I have to be "privileged"
[SCR register][2]
So, how can I enter in privileged mode? Is it really necessary enter in this mode only for interrupt configuration?
What I've done in code is
SCB->CCR |= 0x02; // USERSETMPEND = 1. But I must be "privileged"
HAL_NVIC_EnableIRQ(EXTI0_IRQn); // enable interrupt line
.... some code....
... ...
if(my_software_trigger)
{
my_software_trigger = 0;
NVIC->STIR = EXTI0_IRQn; // triggers interrupt??
}
Is it the correct approach? Anyone has experience in this matter? Any help is really appreciatedd..
P.s. Sorry for my english
Marco.

I can't get data by I2C bus in Android Things

I can't get data by I2C bus in Android Things on Raspberry Pi 3.
I connect Android Things on RPi and DS18B20(Temperature Sensor).
Connect to RPi
and run the I2C address scan App (https://github.com/dennisg/i2c-address-scanner), but can't find available address.
for (int address = 0; address < 256; address++) {
//auto-close the devices
try (final I2cDevice device = peripheralManagerService.openI2cDevice(BoardDefaults.getI2cBus(), address)) {
try {
device.readRegByte(TEST_REGISTER);
Log.i(TAG, String.format(Locale.US, "Trying: 0x%02X - SUCCESS", address));
} catch (final IOException e) {
Log.i(TAG, String.format(Locale.US, "Trying: 0x%02X - FAIL", address));
}
} catch (final IOException e) {
//in case the openI2cDevice(name, address) fails
}
}
How do I get data by I2C?
The linked test project appears to use the I2C protocol poorly in several ways.
First, it makes the assumption that there is only a single I2C bus on a particular board. Although that is true now, it may not scale to additional SOMs that support Android Things in the future.
Second, it assumes the register address to read from (0x00). This may have worked for whatever device the developer started with, but a large number of I2C peripherals may not respond to that address.
You should take a look at the datasheet for this device. After a cursory examination, it seems that there is no register corresponding to 0x00. Additionally, it has a custom read flow that would make it difficult to use the snippet above. The microcontroller getting these values on your sensor probably throws them away and returns no signal.
It may be useful to read through the datasheet again. It seems like the sensor is "one-wire" instead of I2C. While the two protocols may be similar, using the built in readByte method may make some assumptions in the data transmission that may not match the peripheral protocol exactly.
As Nick Felker wrote in his answer DS18B20 has 1-Wire interface and you can't connect it to Raspberry Pi with Android Things directly. You should use industrial (e.g DS2482-100) or custom MCU-based (like in that project) 1-Wire <-> I2C converter, or other (e.g. USB <-> 1-Wire, UART<-> 1-Wire) converters.

max732x.c I2C IO Expander + GPIO Keys w/ Linux Device Tree not working

I'm working with a Freescale MX6 and a 3.10.31 Freescale modified kernel. I have a Maxim MAX7325 used as an IO expander, which has pushbuttons attached to P0-P2. The interrupt line from the 7325 is attached to the GPIO_3 pad (which I believe is GPIO1_3...)
I set up the 7325 and gpio-keys in the device tree like this:
max7325_reset: max7325-reset {
compatible = "gpio-reset";
reset-gpios = <&gpio5 16 GPIO_ACTIVE_LOW>;
reset-delay-us = <1>;
#reset-cells = <0>;
};
gpio-keys {
compatible = "gpio-keys";
sw2 {
gpios = <&max7325 2 GPIO_ACTIVE_LOW>;
linux,code = <30>; //a
gpio-key,wakeup;
};
};
and
&i2c1 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1_2>;
status = "okay";
max7325: gpio#68 {
compatible = "maxim,max7325";
reg = <0x68>;
gpio-controller;
#gpio-cells = <2>;
resets = <&max7325_reset>;
gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;
interrupt-parent = <&gpio1>;
interrupts = <3 2>;
};
};
What appears to happen is when probe for the MAX7325 driver is called, client->dev.platform_data is NULL. Because of this, when max732x_irq_setup is called later, it doesn't set up the chip->gpio_chip.to_irq pointer to point at max732x_gpio_to_irq function (presumably because it doesn't have the right info for this to work.) Later, when gpio_keys
tries to config the first input, it fails when it tries to set up the interrupt and none of the other keys get set up.
gpio-keys gpio-keys.20: Unable to get irq number for GPIO 242, error -6
I did determine using the /sys interface that P0 maps to GPIO 240, so yeah, GPIO 242 is the sw2 GPIO-KEY I was trying to set up.
I'm wondering, does this driver not work with a device tree? I don't see it trying to get any device tree properties, but other IO expander drivers I looked at didn't either, so I thought maybe the I2C core is reading the device tree and supposed to fill in the platform_data from there somehow before it calls the driver's probe function (?)
I'm fairly new at this, so any help would be appreciated. =) I did read a few of the Device Tree docs online, but I'm thinking this is something fairly specific that I'm not doing correctly, which they don't cover... (?)
I do have CONFIG_GPIO_MAX732X_IRQ configured in the kernel... and I did at one point try setting the interrupt-controller property for the max7325 I2c1 node, but I wasn't sure that was needed (?)
MAX732x device tree support
Driver you are using won't work with data from device tree. I have added device tree support to this driver and sent it to kernel mailing lists for review, but they are not merged yet. See this thread (total 4 patches):
You can either apply those patches to your branch or wait for them to get into upstream kernel and then cherry-pick them from there (into your branch).
Bindings documentation (see patches above) shows how to create device tree declaration for MAX732x. In your case it may look like this:
&i2c1 {
expander: max7325#68 {
compatible = "maxim,max7325";
reg = <0x68>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
interrupt-parent = <&gpio1>;
interrupts = <3 2>;
};
};
Another way for you to use this driver (without patches above) is to specify platform data in board file for your board. I believe it should be one of next files:
arch/arm/mach-imx/mach-imx6q.c
arch/arm/mach-imx/mach-imx6sl.c
arch/arm/mach-imx/mach-imx6sx.c
You can find an example how to do so here: arch/arm/mach-pxa/littleton.c, line 394.
But it may be not reliable way: I tried to do so and had some issues with i2c buses numbers (didn't look too much in that way though). It also looks bad to scatter devices' definitions between board file and dts file. So I strongly recommend you to use patches above.
Answers to questions
What appears to happen is when probe for the MAX7325 driver is called, client->dev.platform_data is NULL.
It happens because driver was binded with device declaration from device tree file rather than from board file. In that case driver should use client->dev.of_node instead of client->dev.platform_data. Just see how it's done in my patch above.
You can read more about how binding/matching/instantiating happens in kernel documentation here:
Documentation/i2c/instantiating-devices
Documentation/devicetree/usage-model.txt
I thought maybe the I2C core is reading the device tree and supposed to fill in the platform_data from there somehow before it calls the driver's probe function (?)
No. When binding is happening, client->irq being automatically populated in I2C core (before driver's probe function being called). Properties like gpio_base and irq_base -- you don't need them in case when data came from device tree.
I did at one point try setting the interrupt-controller property for the max7325 I2c1 node, but I wasn't sure that was needed (?)
MAX7325 issues interrupt to your SoC when it detects changes on input lines (more specifically, on open-drain I/O ports configured as inputs).
So if you want your driver to generate separate interrupts for each input I/O line (so that other drivers can consume them), you should specify "interrupt-controller" and "#interrupt-cells" properties. But for this you need all patches mentioned above to be applied.
Patches status
Now all mentioned patches were merged into upstream kernel (v4.0 and later):
gpio: max732x: Add device tree support
gpio: max732x: Rewrite IRQ code to use irq_domain API
gpio: max732x: Fix possible deadlock
gpio: max732x: Add DT binding documentation
Also notice that there are some new patches were made on top of my patches. You can watch them here.

Linux and reading and writing a general purpose 32 bit register

I am using embedded Linux for the NIOS II processor and device tree. The GPIO functionality provides the ability to read and or write a single bit at a time. I have some firmware and PIOS that I want to read or write atomically by setting or reading all 32 bits at one time. It seems like there would be a generic device driver that if the device tree was given the proper compatibility a driver would exist that would allow opening the device and then reading and writing the device. I have searched for this functionality and do not find a driver. One existing in a branch but was removed by Linus.
My question is what is the Linux device tree way to read and write a device that is a general purpose 32 bit register/pio?
Your answer is SCULL
Character Device Drivers
You will have to write a character device driver with file operations to open and close a device. Read, write, ioctl, and copy the contents of device.
static struct file_operations query_fops =
{
.owner = THIS_MODULE,
.open = my_open,
.release = my_close,
.ioctl = my_ioctl
};
Map the address using iomem and directly read and write to that address using rawread and rawwrite. Create and register a device as follows and then it can be accessed from userspace:
register_chrdev (0, DEVICE_NAME, & query_fops);
device_create (dev_class, NULL, MKDEV (dev_major, 0), NULL, DEVICE_NAME);
and then access it from userspace as follows:
fd = open("/dev/mydevice", O_RDWR);
and then you can play with GPIO from userspace using ioctl's:
ioctl(fd, SET_STATE);