Beaglebone devm_pwm_get returns ENODEV - linux

I am experimenting with a pwm-driver for the Beaglebone black, based of this one.
As I am using Yocto with the meta-bbb layer, I had to rewrite the .dtsi:
&am33xx_pinmux {
bbb_pwm_P8_13_pins: bbb_pwm_P8_13_pins {
pinctrl-single,pins = <0x024 0x4>; /* P8_13 (ZCZ ball T10) | MODE 4 */
};
};
/ {
bbb-pwm#123 {
compatible = "tfe,bbb_pwm-1.00.a";
pwms = <&ehrpwm2 1 0 1>;
pwm-names = "PWM_P8_13";
pinctrl-names = "default";
pinctrl-0 = <&bbb_pwm_P8_13_pins>;
enabled = <0>;
duty = <0>;
status = "okay";
};
};
However, during the driver-probe function, the call
pwm_test->pwm = devm_pwm_get(&pdev->dev, NULL);
returns ENODEV:
[ 7.538249] pinctrl-single 44e10800.pinmux: found group selector 15 for bbb_pwm_P8_13_pins
[ 7.538278] pinctrl-single 44e10800.pinmux: request pin 9 (44e10824.0) for bbb-pwm#123
[ 7.538291] pinctrl-single 44e10800.pinmux: enabling bbb_pwm_P8_13_pins function15
[ 7.538366] Loading bbb_pwm
[ 7.541304] bbb-pwm bbb-pwm#123: obtain a copy of previously claimed pinctrl
[ 7.541321] bbb-pwm bbb-pwm#123: Unable to request PWM (err = -19)
I found that the error-code is returned by a sub-call of devm_pwm_get:
static int pwm_device_request(struct pwm_device *pwm, const char *label)
{
/* .... */
if (!try_module_get(pwm->chip->ops->owner))
return -ENODEV;
/* ... */
}
However, since I am fairly new to Linux-drivers, I do not understand why this happens. Any clues?

It turned out that the lower-level PWM-driver (EHRPWM) was disabled in the kernel. Enabling it using menuconfig and ensuring that EHRPWM and EPWMSS was enabled in the device tree solved my problem:
Using the meta-bbb layer, I simply accessed menuconfig through bitbake:
bitbake virtual/kernel -c menuconfig
and loaded the defconfig located /meta-bbb/recipes-kernel/linux/linux-stable-4.4/beaglebone/defconfig
I also added the following line to my local.conf
PREFERRED_VERSION_linux-stable = "4.4"
Here is my dtsi:
&am33xx_pinmux {
bbb_pwm_P8_13_pins: bbb_pwm_P8_13_pins {
pinctrl-single,pins = <0x024 0x4>; /* P8_13 (ZCZ ball T10) | MODE 4 */
};
};
&ehrpwm2 {
status = "okay";
};
&epwmss2 {
status = "okay";
};
/ {
bbb-pwm#123 {
compatible = "tfe,bbb_pwm-1.00.a";
pwms = <&ehrpwm2 1 0 1>;
pwm-names = "PWM_P8_13";
pinctrl-names = "default";
pinctrl-0 = <&bbb_pwm_P8_13_pins>;
enabled = <0>;
duty = <0>;
status = "okay";
};
};

Related

How to use u-boot verified boot with multiple keys for signature verification?

I'm trying to use u-boot verified boot to support my use case. Ideally, I want to have two set of kernel, ramdisk, dtb 1). for production use only, 2). for development scenario.
I generated two keys with corresponding public key - dev.key, dev.crt, prod.key, prod.crt.
For testing I created a FIT source file as following, but the u-boot.dtb generated only put production key in the binary, there is no sign of development key (the structure is there but it is missing rsa,r-squared and rsa,modulus). Any idea hwo to do this correctly? thank you!
/dts-v1/;
/ {
description = "fitImage for Tegra TX2";
#address-cells = <1>;
images {
kernel-1 {
description = "Linux kernel";
data = /incbin/("Image");
...
hash-1 {
algo = "sha256";
};
};
fdt-1 {
description = "DTB for Tegra TX2";
data = /incbin/("tegra186-base.dtb");
...
hash-1 {
algo = "sha256";
};
};
ramdisk-1 {
description = "Ramdisk Image for Tegra TX2";
data = /incbin/("initrd");
...
hash-1 {
algo = "sha256";
};
};
};
configurations {
default = "conf-1";
conf-1 {
description = "Production build";
kernel = "kernel-1";
fdt = "fdt-1";
ramdisk = "ramdisk-1";
signature-1 {
algo = "sha256,rsa2048";
key-name-hint = "prod";
sign-images = "kernel", "fdt", "ramdisk";
};
};
conf-2 {
description = "Development build";
kernel = "kernel-1";
fdt = "fdt-1";
ramdisk = "ramdisk-1";
signature {
algo = "sha256,rsa2048";
key-name-hint = "dev";
sign-images = "kernel", "fdt", "ramdisk";
};
};
};
};
With my limited test, the only way mkimage command adds two keys into u-boot.dtb is the following setup. Essentially the second key just used as a backup option. This seems to corresponding to U-boot document. But this is not fit for my use case.
The document says
key-name-hint: Name of key used for signing. This is only a hint since it
is possible for the name to be changed. Verification can proceed by checking
all available signing keys until one matches.
"
/dts-v1/;
/ {
description = "fitImage for Tegra TX2";
#address-cells = <1>;
images {
kernel-1 {
description = "Linux kernel";
data = /incbin/("Image");
...
hash-1 {
algo = "sha256";
};
};
fdt-1 {
description = "DTB for Tegra TX2";
data = /incbin/("tegra186-base.dtb");
...
hash-1 {
algo = "sha256";
};
};
ramdisk-1 {
description = "Ramdisk Image for Tegra TX2";
data = /incbin/("initrd");
...
hash-1 {
algo = "sha256";
};
};
};
configurations {
default = "conf-1";
conf-1 {
description = "Production build";
kernel = "kernel-1";
fdt = "fdt-1";
ramdisk = "ramdisk-1";
signature-1 {
algo = "sha256,rsa2048";
key-name-hint = "prod";
sign-images = "kernel", "fdt", "ramdisk";
};
signature-2 {
algo = "sha256,rsa2048";
key-name-hint = "dev";
sign-images = "kernel", "fdt", "ramdisk";
};
};
};
};
You can use ubootpubkey to embed keys to your u-boot dts file at u-boot compilation time

DTS File to disable LCD and use it's GPIO in iMX6ULL

I am using the Toradex system-on-module colibri imx6ULL with a custom board.
I am trying to disable the LCD and use it's GPIOs for my sensors. I have followed the answer in this link. I got stuck with one of the suggestion in the answer.
In addition to assigning these pings to an iomuxc pinctrl group, you'll also need to assign the pinctrl group to an enabled node for them to get initialized. You can create a new node specifically for this purpose if you'd like.
What does that line mean? Do I need to create a dummy node with status property set to okay?
Can I change of the name appearing in /dev/ for uart port?
How can I enable JTAG in my custom board?
My device tree source file is below:
/dts-v1/;
#include "imx6ull-colibri-nonwifi.dtsi"
#include "imx6ull-colibri-eval-v3.dtsi"
/ {
model = "Toradex Colibri iMX6ULL 256MB on Colibri Evaluation Board V3";
compatible = "toradex,colibri_imx6ull-eval", "fsl,imx6ull";
&uart1 {
status = "okay";
};
&uart2 {
status = "okay";
};
&uart3 {
status = "okay";
};
&uart4 {
status = "disabled";
};
&uart5 {
status = "disabled";
};
&ecspi1 {
status = "okay";
};
&i2c1 {
status = "okay";
/* M41T0M6 real time clock on carrier board */
rtc: m41t0m6#68 {
status = "disabled";
};
};
&pwm1 {
status = "okay";
};
&pwm2 {
status = "okay";
};
&lcdif {
status = "disabled";
};
&iomux {
imx6ull-colibri {
pinctrl_additionalgpio: additionalgpios {
fsl,pins = <
MX6UL_PAD_UART2_RTS_B__GPIO1_IO23 0x14 // Pin 34 => GPS SafeBoot
MX6UL_PAD_CSI_DATA00__GPIO4_IO21 0x14 // Pin 101 => 1V8 Power Supply Enable
MX6UL_PAD_LCD_ENABLE__GPIO3_IO01 0x14 // Pin 44 => GPS EXINT
MX6UL_PAD_LCD_DATA07__GPIO3_IO12 0x14 // Pin 46 => GPS RST
MX6UL_PAD_LCD_DATA09__GPIO3_IO14 0x14 // Pin 48 => UNUSED
MX6UL_PAD_LCD_DATA06__GPIO3_IO11 0x14 // Pin 80 => SX1301 RST
>;
};
};
};
};
The device tree imx6ull-colibri-nonwifi.dtsi can be found over here.
The device tree imx6ull-colibri-eval-v3.dtsi can be found over here.
EDIT:
I have tried few times on my own after reading some documents online on dts. Find the latest version of my dts below. I have also found out SPI is not working in my board so that I have edited my dts to include spi.
I have added a dummy node to enable gpio.
/dts-v1/;
#include "imx6ull-colibri-nonwifi.dtsi"
#include "imx6ull-colibri-eval-v3.dtsi"
/ {
model = "Toradex Colibri iMX6ULL 256MB on Colibri Evaluation Board V3";
compatible = "toradex,colibri_imx6ull-eval", "fsl,imx6ull";
&uart1 {
status = "okay";
};
&uart2 {
status = "okay";
};
&uart3 {
status = "okay";
};
&uart4 {
status = "disabled";
};
&uart5 {
status = "disabled";
};
&ecspi1 {
status = "okay";
};
&i2c1 {
status = "okay";
/* M41T0M6 real time clock on carrier board */
rtc: m41t0m6#68 {
status = "disabled";
};
};
&pwm1 {
status = "okay";
};
&pwm2 {
status = "okay";
};
&lcdif {
status = "disabled";
};
gpio_additional {
pinctrl-name = "default";
pinctrl-0 = <&pinctrl_additionalgpio>;
status = "okay";
};
&ecspi1 {
status = "okay";
};
&iomux {
imx6ull-colibri {
pinctrl_additionalgpio: additionalgpios {
fsl,pins = <
MX6UL_PAD_UART2_RTS_B__GPIO1_IO23 0x14 // Pin 34 => GPS SafeBoot
MX6UL_PAD_CSI_DATA00__GPIO4_IO21 0x14 // Pin 101 => 1V8 Power Supply Enable
MX6UL_PAD_LCD_ENABLE__GPIO3_IO01 0x14 // Pin 44 => GPS EXINT
MX6UL_PAD_LCD_DATA07__GPIO3_IO12 0x14 // Pin 46 => GPS RST
MX6UL_PAD_LCD_DATA09__GPIO3_IO14 0x14 // Pin 48 => UNUSED
MX6UL_PAD_LCD_DATA06__GPIO3_IO11 0x14 // Pin 80 => SX1301 RST
>;
};
};
};
};
1) It means you need to add the pinctrl-group e.g. the one you have created pinctrl_additionalgpio to a node.
I'll take for instance the lcdif node you have disabled in you device-tree to illustrate a pinctrl-group added to a node. In this example, pinctrl_lcdif_dat and pinctrl_lcdif_ctrl are added to the lcdif node:
&lcdif {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lcdif_dat
&pinctrl_lcdif_ctrl>;
};
You have to either create a node of your own and add the pinctrl-group or find a suitable node, e.g.:
myadditionalgpio {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_additionalgpio>;
};
2) I have not ever got as far as changing the name of the device. If all you need is to have an alternative name, you can use a udev rule to create a symlink:
/etc/udev/rules.d/rename-uart.rules
KERNEL=="ttymxc0", SYMLINK+="test_serial"
Then you will have a /dev/test_serial device that points to /dev/ttymxc0.
3) You can have a look at the generic JTAG Toradex documentation https://developer.toradex.com/knowledge-base/jtag.

Register snd-soc-dummy in a device tree

I'm trying to register the ALSA dummy codec provided in soc-utils in my device tree source file, to use it with an i2s device driver (sun8i-i2s).
I've tried to set the sound-dai field in my i2s configuration as explained here : https://patchwork.kernel.org/patch/7679391/, but the device driver fails to find the dai name when reading the device tree.
I've found two workarounds, which consists in either writing my own dummy codec and giving it to the device tree :
/ {
stupid-codec {
#sound-dai-cells = <0x00000000>;
compatible = "linux,snd-soc-stupid";
status = "okay";
linux,phandle = <0x0000dead>;
phandle = <0x0000dead>;
};
...
};
...
&i2s0 {
#sound-dai-cells = <0x00000000>;
compatible = "allwinner,sun8i-h3-i2s";
sound-dai = <0x0000dead>;
status = "okay";
};
Or force-link the codec in the device driver and have no sound-dai field in the device :
device tree :
&i2s0 {
// No sound-dai
status = "okay";
};
i2s driver :
static int sun8i_card_create(struct device *dev, struct priv *priv)
{
struct snd_soc_card *card;
...
// Skip the part where it's reading the device tree
#if 0
codec->of_node = sun8i_get_codec(dev);
if (!codec->of_node) {
dev_err(dev, "no port node\n");
return -ENXIO;
}
DBGOUT("%s: codec_name=\"%s\"\n", __func__, codec->of_node->name);
if(snd_soc_of_get_dai_name(dev->of_node, &codec->dai_name) < 0)
{
dev_err(dev, "%s: failed to find dai name, use codec's name as dai name.\n", __func__);
codec->dai_name = codec->of_node->name;
}
DBGOUT("%s: dai_name=\"%s\"\n", __func__, codec->dai_name);
#endif
// Force codec and dai name
codec->name = "snd-soc-dummy";
codec->dai_name = "snd-soc-dummy-dai";
Both kind of work, but it is still a dirty hack, so it would be great if someone had the correct syntax for the dummy in the device tree.
EDIT 2019/10/10
We ended up using a different codec (pcm5102a), which gets implemented separately in the dts :
(in sun8i-h3-nanopi-neo-air.dts)
&i2s0 {
/* sound-dai = <&pcm5102a>; */
status = "okay";
};
(in sun8i-h3-nanopi.dtsi)
pcm5102a: pcm5102a-codec {
#sound-dai-cells = <0>;
compatible = "ti,pcm5102a";
status = "disabled";
};
As for the use of snd-soc-dummy, I couldn't make it work properly, but I noticed that the generic linux driver seems to use a hardcoded string to register it :
https://github.com/torvalds/linux/blob/master/sound/soc/generic/simple-card.c

Linux I2C Kernel Driver

I have a requirement to create a Linux Kernel Driver to interface with a bunch of MCU's over I2C, through an Interface Board. Because they would be many in number, i.e around 1-18, we are utilising a NXP / TI I2C Multiplexer.
I have imported the NXP / TI I2C Multiplexer kernel driver and have incorporated the same in the DTS file. I have been successfully able to list all the I2C Multiplexers as different i2c-x nodes.
The MCU's all are using the same Address 0x08. And I create a kernel driver which creates a hwmon + sysfs interface for it.
However, the driver upon insmod only triggers __init function. And does not bother with probe().
Upon referring to many documentations I was able to trigger probe function only when am inserting
static struct i2c_board_info xxxx_i2c_devices[] = {
{
I2C_BOARD_INFO("xxxx", 0x08),
},
};
And its corresponding
i2c_register_board_info(0, xxxx_i2c_devices, ARRAY_SIZE(xxxx_i2c_devices));
However, this creates only one instance in HWMON and not several as I imagined it to be. I have referred https://www.kernel.org/doc/Documentation/i2c/instantiating-devices
Without the changes in board init, I tried to utilize the Method 3, however kernel doesn't even call the probe() and detect function(), only the __init function of the driver.
Am following the driver -
https://github.com/1119553797/sprd-kernel-common/blob/sprdb2g_gonk4.0/drivers/hwmon/w83l785ts.c
Would post the entire kernel driver if needed, for reference am using the Kernel 3.0.8, a custom board using board level changes to the same mentioned kernel.
Ok, after extensive googling and patching different methods heres a workaround.
First and foremost in the DTS, we can assign the I2C address in the Mux addressing directly. For .e.g.
i2c#0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
adc0: nau7802#2a {
compatible = "nuvoton,nau7802";
reg = <0x2a>;
nuvoton,vldo = <3000>;
};
};
i2c#1 {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
adc1: nau7802#2a {
compatible = "nuvoton,nau7802";
reg = <0x2a>;
nuvoton,vldo = <3000>;
};
};
i2c#2 {
#address-cells = <1>;
#size-cells = <0>;
reg = <2>;
adc2: nau7802#2a {
compatible = "nuvoton,nau7802";
reg = <0x2a>;
nuvoton,vldo = <3000>;
};
};
Then in the driver, in order to identify with the VendorID,ProductID structure as in the above example "nuvoton,nau7802", we have to make the following changes :-
static const struct i2c_device_id nau7802_i2c_id[] = {
{ "nau7802", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, nau7802_i2c_id);
static const struct of_device_id nau7802_dt_ids[] = {
{ .compatible = "nuvoton,nau7802" },
{},
};
MODULE_DEVICE_TABLE(of, nau7802_dt_ids);
static struct i2c_driver nau7802_driver = {
.probe = nau7802_probe,
.remove = nau7802_remove,
.id_table = nau7802_i2c_id,
.driver = {
.name = "nau7802",
.of_match_table = nau7802_dt_ids,
},
};
The part "adc1" etc can be simply skipped. "MODULE_DEVICE_TABLE(of," is meant to be device_tree information, from what I could gather.
Please do let me know if you find a better method which does not require a DTS & board _init changes.

Difference between spi_driver.id_table and spi_driver.driver.of_match_table

I'm currently trying to understand how linux drivers work. As far as I know, A driver's probe/init function is called when the kernel parses the corresponding .compatible string in the device tree. However, in the arizona-spi driver it looks like there are multiple compatible strings referenced in different members:
static const struct spi_device_id arizona_spi_ids[] = {
{ "wm5102", WM5102 },
{ "wm5110", WM5110 },
{ },
};
MODULE_DEVICE_TABLE(spi, arizona_spi_ids);
static struct spi_driver arizona_spi_driver = {
.driver = {
.name = "arizona",
.owner = THIS_MODULE,
.pm = &arizona_pm_ops,
// Contains e.g. "wlf,wm5102"
.of_match_table = of_match_ptr(arizona_of_match),
},
.probe = arizona_spi_probe,
.remove = arizona_spi_remove,
.id_table = arizona_spi_ids, // Contains "wm5102" and "wm5110"
};
This is an excerpt from here.
So what is the difference between arizona_spi_driver.id_table and arizona_spi_driver.driver.of_match_table?
There are several mechanism for driver matching. The id_table is intended to be used for finding a match from stripped device-tree entries (without vendor part), while of_match_table is used to find a match from full device-tree entries (the ones with vendor part).
If you check, arizona_of_match is defined as this:
const struct of_device_id arizona_of_match[] = {
{ .compatible = "wlf,wm5102", .data = (void *)WM5102 },
{ .compatible = "wlf,wm5110", .data = (void *)WM5110 },
{ .compatible = "wlf,wm8280", .data = (void *)WM8280 },
{ .compatible = "wlf,wm8997", .data = (void *)WM8997 },
{},
};
wlf is the vendor part for this case, while arizona_spi_ids doesn't contain the vendor part.
Hence, if you have something like this in your device tree:
compatible = "myvendor,wm5102"
Your device will match against id_table but not against of_match_table since the vendor is different.
The kernel will do matching against of_match_table first before check id_table (see spi_get_device_id in here). The device matching priority is: of_match_table > acpi_driver > id_table.

Resources