How to - device tree node for platform/miscdevice - linux-device-driver

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.

Related

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.

Reading/writing SPI devices

(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.

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.

Problems using a MCP3008 and a MCP23S17 on SPI with WebIOPi

I'm very new to WebIOPi and I'm trying my first tests. First of all I apologize for my english.
I'm trying to get to work a RPi with a MCP3008 on CE0 and a MCP23S17 on CE1 with SPI bus.
My problem is that devices only work when connected on CE1 (so, when 23017 is on CE0 I am not able to set pins to be inputs or outputs and to set it on 1 or 0, but 3008 is on CE1 and I see its levels changing. When - vice versa - 23017 is on CE1 it is fully functional, but 3008 outputs stay still).
Due to this, I think it is not an hardware issue (I don't have much expertise in electronics, but luckily I don't build my circuits by myself :) ), I think it is a problem in WebIOPi config. Here is my WebIOPi config:
[DEVICES]
mcp1 = MCP23S17 chip:1 slave:0x27
adc0 = MCP3008 chip:0
I only added these two lines to my config file.
I did not touch anything else of my original WebIOPi installation.
In this case (adc0 fully functional, mcp1 not working), when loading the WebIOPi devices monitor I see adc0 levels working good and mcp1 pins randomly changing between being a input and an output and from 0 and 1.
May it be a config error?
Use python and spidev module instead! Look my answer on another thread for function for the mcp3008 chip.

How to ping meter with Modbus

I am trying to ping a Socomec meter using the Modbus protocol, having researched, I found NModbus, a C# library. I have never used libraries or C# before (normally Java), but I have to dive right in.
I set myself up with Visual Studio Express for C# and installed .Net. I have copied then contents of the NModbus file into my project folder and added the references to the two main DLLs. Its didn't work with .Net 4, but I retargeted to 3.5 (and removed the Microsoft.Csharp reference) and things seemed to compile.
I am using this sample, below, to attempt to connect to the slave device. When I run this, and set the startAdress variable to the desired one (found in Socomec documentation) however all I get is a blank console window.
In short, am I using the correct method/parameters, is my setup/code incorrect? How do I connect to this meter?
My code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using Modbus.Data;
using Modbus.Device;
using Modbus.Utility;
namespace NModbus
{
class SerialMaster
{
static void Main(string[] args)
{
ModbusSerialAsciiMasterReadRegisters();
}
public static void ModbusSerialAsciiMasterReadRegisters()
{
using (SerialPort port = new SerialPort("COM1"))
{
// configure serial port
port.BaudRate = 9600;
port.DataBits = 8;
port.Parity = Parity.None;
port.StopBits = StopBits.One;
port.Open();
// create modbus master
IModbusSerialMaster master = ModbusSerialMaster.CreateAscii(port);
byte slaveId = 1;
ushort startAddress = 50536;
ushort numRegisters = 5;
// read five registers
ushort[] registers = master.ReadHoldingRegisters(slaveId, startAddress, numRegisters);
for (int i = 0; i < numRegisters; i++)
Console.WriteLine("Register {0}={1}", startAddress + i, registers[i]);
Console.ReadLine();
}
// output:
// Register 1=0
// Register 2=0
// Register 3=0
// Register 4=0
// Register 5=0
}
}
}
Why don't you use some Java MODBUS library when you are already familiar with Java? I haven't worked with Socomec meters, but in general for MODBUS devices you need to know the protocol and addresses you are interested in. Then try to read tags from the device with some tool that you know is working well, like MODPOLL. Then when you get usable values as expected, you go to programming the polling connection in any language you like. Otherwise, you risk to loose a lot of time wondering what's going on.
One hint... From your code I see that you are acting as MODBUS ASCII serial master. Although such devices exist, 95% of RS232/RS485 devices I worked with were MODBUS RTU. Read specification if you don't know the difference.
You can run Java applications as a Windows service. There is a Tomcat Java service starter that I use with my company's Java application. You have create a method that will be called to stop the service, but that's just a method.
Here's the line I use to install my application as a service --
"%~dp0windows\tomcat6" //IS//%1 --DisplayName %1 --Description "gmServer for %1" ^
--JavaHome "%JAVA_HOME%" --Classpath "%PR_CLASSPATH%" --LogPrefix gmserver ^
--StartMode jvm --StopMode jvm --Jvm auto --StartPath "%~dp0." ^
--LogPath "%~dp0." --LogLevel debug --StdOutput %1.out --StdError %1.err ^
--StartClass greenMonitor.gmServer --StartParams -I#%I#-u#3600 ^
--StopMethod windowsService --StopParams stop --StopTimeout 10
The caret characters ("^") are line continuations characters in .BAT files. You should be able to find the meanings of the Tomcat command line options with the Tomcat documentation.
And for a Java-based Modbus library, complete with lots of handy programs you can use to test the connection, check out j2mod on Sourceforge. My company did a fork of jamod, along with a bunch of cleanups and that was the result.