Enabling PWM sysfs entry - linux

I am trying to enable pwm under /sys/class/pwm/. What I am anticipating under this is something like pwmchip0/export etc. I have gone through the following things:
Checked that PWM_SYSFS is =y in the config.
The dtsi file has the right entries for the pwm.
The driver for pwm is being compiled properly.
But when I run build on the target I can see only /sys/class/pwm but nothing underneath.
I have not touched the dts file at all.
If anyone can point me towards the right direction or point out list of things to check for starter I would be grateful.
Please ask if I have missed anything to mention in the question.

This was actually simple. The reason the PWM entry was missing is because of the fact that the driver probe was not being called at all which means the kernel had no idea there exits a PWM driver. This I noticed from the kernel logs and extra printks in the driver code.
The reason the PWM driver probe was not being called by the kernel is that the device was not enabled in the dtsi file:
pwm: pwm#xxxxxxxx {
compatible = "aaa,bbb-pwm";
reg = <0xxxxxxxxx 0x200>;
status = "disabled";
};
To enable it I had to modify (add an entry for PWM) the .dts file:
&pwm {
status = "okay";
};
In my case the driver was already written, so I could see the PWM entry immediately after this point. If you are writing a new driver you might have to create all the necessary sysfs entries as required.

Related

Linux: writing to the i2c/SMBus

I have a problem with the i2c/SMBus on a Linux System with an Intel Apollo Lake processor. I am trying to read/write from/to an EEPROM but I face some issues. My EEPROM is located at the address 0x56, and I am able to watch the Bus with my Logic Analyzer.
When I try to read from the device via i2ctools (i2cget) the System behaves as expected. My issue occurs when I try to perform a write command via i2cset for example. i2cset ends with an error (Write failed). Because I am able to watch the Bus electrically I can also say that all lines stay HIGH and the Bus is not touched. I was able to activate the dev_dbg() functions in the i2c driver i2c_i801 and when I perform i2cset I am able to find (dmesg) the debug message:
[ 765.095591] [2753] i2c_i801:i801_check_post:433: i801_smbus 0000:00:1f.1: No response
When running my minimal I²C Python code using the smbus2 lib, I get the following error message and the above mentioned debug message:
from smbus2 import SMBus
bus = SMBus(0)
b = bus.read_byte_data(86,10) #<- This is performed
b = bus.write_byte_data(86,10,12) #<- This is not performed
bus.close()
Error:
File "usr/local/lib/python3.8/dist-packagers/smbus2-0.4.0-py3.8.egg/smbus/smbus2.py", line 455, in write_byte_data
ioctl(self.fd, I2C_SMBUS, msg)
OSERROR: [Errno 6] No such device or adress
A big hint for me is that I am not able to perform a write command in the address space form 0x50 to 0x57. My guess is that some driver locks the address space to prevent write command to that "dangerous" area.
My question is: "Does anyone know this kind of behavior and is there a solution so that I can write to my EEPROM at address 0x56? OR Is there a lock surrounding the i2c adress space from 0x50 to 0x57 and who is my opponent?"
I am kind of a newbie to the whole driver and kernel world so please be kind and it is quite possible that I made a beginner mistake.
I would appreciate hints and tips I can look after surrounding my problem.
It seems that I found the cause of my problem. In this Forum post is described that Intel changed a configuration Bit at the SMBus controller.
OK, I know what's going on.
Starting with the 8-Series/C220 chipsets, Intel introduced a new
configuration bit for the SMBus controller in register HOSTC (PCI
D31:F3 Address Offset 40h):
Bit 4 SPD Write Disable - R/WO.
0 = SPD write enabled.
1 = SPD write disabled. Writes to SMBus addresses 50h - 57h are
disabled.
This badly documented change in the configuration explains the issues.
One Challenge is, that to apply and enable changes to the SPD-write Bit the System needs to be rebooted. Unfortunately while rebooting the BIOS will change the Bit back to the default. The only solution seems to be an adaption in the BIOS.
For me, this issue is resolved. I just wanted to share this information in case someone faces the same issues.

Dallas 1 Wire Protocol with Yocto/Raspberry Pi 3

I have been trying to get a custom Yocto build off the ground for some time now. The goal is to connect a DS18b20 thermometer to the GPIO pins and test that it is indeed working. I have gotten as far as building out the base image and adding on all of the software packages I needed to it. The problem presents itself when I try to connect and detect the thermometer with my custom firmware image. It boots fine, networking works, wifi works, have not tried BT yet as I don't need it, but the GPIO pins are the ones that are not proving to be of help.
I am using a 4.9.x Linux Kernel on it. Is it recommended I downgrade to a 4.4.x Linux Kernel? I've pretty much run out of ideas at this point, just need some help to figure it out. f
This device is supported by the kernel, no need to mess with searching or writing your own w1 driver.You will need to ensure the CONFIG_W1_SLAVE_THERM, CONFIG_W1_MASTER_GPIO and CONFIG_W1 are set in you kernel config (consult the Yocto kernel documentation for setting this one-time or in a way that will persist over several builds).
This usually leaves the only remaining gap being which GPIO pin is used for w1. Without knowing which device you are using I can only provide some pointers. The connection is defined via a platform data. This can be defined in the device tree, for example with a c.h.i.p.
onewire {
compatible = "w1-gpio";
gpios = <&pio 3 2 GPIO_ACTIVE_HIGH>; /* PD2 */
pinctrl-names = "default";
pinctrl-0 = <&chip_w1_pin>;
};
Where PD2 == LCD-D2 on the header.
Alternatively it can be defined in the mach-* in the kernel, for example
static struct w1_gpio_platform_data w1_gpio_platform_data = {
.pin = GPIO_ONE_WIRE,
.is_open_drain = 0,
};
static struct platform_device raumfeld_w1_gpio_device = {
.name = "w1-gpio",
.dev = {
.platform_data = &w1_gpio_platform_data
}
};
A google search of 'w1-gpio map gpio' should return more and better details. If you can use the device tree approach, that is what they are made for. Just know that the kernel code doesn't cycle through the GPIO pins looking for connected w1 devices, this mapping has to be set.
If the device is attached and working you will be able to get its value by doing 'cat /sys/bus/w1/devices/28*/w1_slave'. If you are using python you can use https://github.com/timofurrer/w1thermsensor to make reading the temperature easy. Or use equivalent libraries for your preferred language.

IRQCHIP_DECLARE: init function is not being run

I am trying to use the Xilinx interrupt controller driver in an embedded ARM FPGA system I am developing.
(https://github.com/torvalds/linux/blob/master/drivers/irqchip/irq-xilinx-intc.c)
At the end of this driver is the line:
IRQCHIP_DECLARE(xilinx_intc_xps, "xlnx,xps-intc-1.00.a", xilinx_intc_of_init);
I have added an entry in my device tree for the interrupt controller.
xil_intc: xil_intc#41810000 {
compatible = "xlnx,xps-intc-1.00.a";
interrupt-parent = <&intc>;
interrupts = <0x0 0x1e 0x04>;
reg = <0x41810000 0x10000>;
interrupt-controller;
#interrupt-cells = <2>;
xlnx,kind-of-intr = <0x0>;
xlnx,num-intr-inputs = <0x1>;
};
However, from what I can tell, the xilinx_intc_of_init function is never called during startup. I added a pr_info at the beginning of the function, but I never see it called.
The only message that seems to indicate an issue is:
[ 0.177772] irq: no irq domain found for /amba/xil_intc#41810000 !
I have successfully written and compiled other device drivers, added entries in the device tree, and had them load up and show in dmesg, but for some reason I can't get this one to work.
Any suggestions on debugging this?
For what it's worth, I'm compiling the driver into a kernel module, installing using modules_install and have added an entry to /etc/modules to load it on startup.
Edit: I am using a 4.6 kernel.
IRQCHIP_DECLARE(xilinx_intc_xps, "xlnx,xps-intc-1.00.a", xilinx_intc_of_init);
The driver irq-xilinx-intc.c is using the above call to register with the irq subsystem.
If irq driver uses IRQCHIP_DECLARE macro it will follow the below sequence to invoke the xilinx_intc_of_init() (callback function)
start_kernel() –> init_IRQ() --> irqchip_init() --> of_irq_init() --> call-back function (xilinx_intc_of_init)
If The Driver was registered using IRQCHIP_DECLARE it must be compiled into the kernel and the callback function will be invoked at kernel boot time.
It doesn't work as kernel modules/overlay like other device drivers.
I came to the conclusion that loading the irqchip driver from /lib/modules was too late in the boot process.
I ended up rebuilding the entire kernel with a modified configuration to include this driver, and then the initialization worked properly.
I guess the lesson is that IRQCHIP drivers must be compiled into the kernel and don't work as kernel modules like other device drivers? I can't find any documentation that says so, but that's the behavior I observed.

How to set a pin between boot and module load for an embedded Linux?

I am facing an interesting problem. I like to set a pin of my cpu. So far I created a module for controlling the pin. This module is setting the default pin configuration(high). The default pin configuration becomes active when the module is loaded. That is working fine.
Now I like to enable my default pin configuration right away from the start of boot process. To archive that I wrote a patch for the ATMEL bootloader(at91bootstrap) and the uboot(u-boot-at91). This works fine till the moment the kernel starts. At the kernel start the pins is set to the ATMEL default. They pins are defined in the device tree as gpios.
I think I have two possibilities:
1st - patch the /init/main.c at the "right" spot. Where is the right spot?
2nd - modify the device tree to set the GPIOs to an other default value. How to "re set" an gpio a value?
When you modify the pin in u-boot level; it will be override by the kernel. /init/main.c is worse idea and so I think you should not followed this approach
In kernel level if you you want to set the GPIO pin, there are two possibilities (apart from your module)
1) Kernel board file.
2) Device tree file.
Suppose if you want to set the SDIO pin as GPIO in i.MX6 board then you need to modify the code like this.
leds {
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpio_leds>;
red {
gpios = <&gpio7 0 0>;
default-state = "on";
};
MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0 //set the pin as GPIO
For the default state of the pin please refer the datasheet of your processor. And one pin may have different functionalities.
And if you want to use the same pin for some other functionalities instead of GPIO then you can choose on of the below configuration.
MX6QDL_PAD_SD3_DAT5__UART2_RX_DATA //UART2 RX Data pin
MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 //As a GPIO pin
MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA // UART1 RX data
MX6QDL_PAD_SD3_DAT6__SD3_DATA6 //SDIO pin which is default in this case
Please add more details if you are looking for something more (like pin number and device tree file name).

How to deal with linux kernel drivers (for newbies)

I am trying to undestand how to USE linux kernel drivers. One day I wrote linux kernel module for handling interrupts from gpio. Built it with "make" command and loaded it with "insmod" and it worked. But now I am trying to use this ov5642 camera driver.I downloaded the source code. made "make" command in folder with sources and when it built I used "insmod" command to load it. It is now listed in already loaded modules list but I have got no idea how to get grabbed frames.
How can I make it work and access its output ?
In order to capture frames from the module, you need to "probe" your driver with a platform device (i.e. you have to create a platform device in order to call "ov5642_probe" function). If the probe function is being called, and ends successfully reaching to "return 0", you will get a print "Chip ID 0x5642 detected" in dmesg. (You can easily check weather the probe function is being called or not by putting a simple "printk(KERN ERR "### my probe function is being called")" at line number 935 in probe function and check in dmesg. If it is being called, you have to interface the camera properly in order to probe driver successfully.
If probe function fails (i.e. being called but not reaching till "return 0"), then there should be problem with reading the registers of ov5642. Check the i2c connections and power supplies of camera properly (and make sure its power on sequence is performed as mentioned in datasheet) if you get "Chip ID" other than 0x5642 or i2c read fails.
If the probe function is not being called, then you need to create a proper platform_device.
Assuming you are doing this on a custom board where ov5642 module is interfaced.
If you get "Chip ID 0x5642 detected" in dmesg, then you should try with "v4l-utils" package. There are many options available in v4l2-ctl command where you can set format, query capabilities, start stream, grab frame. If you are unable to install v4l-utils on your board, then, you should try https://gist.github.com/maxlapshin/1253534. You can also refer to Documentation/video4linux/ on lxr online or any kernel source offline if you are interested in developing a camera driver.
If you are a newbie, and you want to learn to deal with kernel drivers, refer to http://www.makelinux.net/ldd3/ and specially platform driver documentation under Documentation/driver-model/platform.txt on lxr for creating and probing a platform driver.

Resources