Pin Muxing in linux kernel - linux

I want to do following pin muxing.
i.e USART Tx -> to GPIO -> Back to USART Tx pin inside Linux kernel for some purpose.
I tried to make the PIN as GPIO using gpio_request and gpio_direction_output, so i am able to make that pin as GPIO . But as i want to switch back from GPIO to USART Tx pin, it is not working, I tried following at91_set_A_periph to that pin, still no luck.
Working on kernel : 3.18 and at91 atmel board.

You can have a look at the i2c-imx driver. It does exactly that.
You need to use pinctrl_lookup_state to retrieve the different pinctrl states (one of those being USART Tx and the other one GPIO). Then you can switch between both with pinctrl_select_state.
To sum it up, you'd have something like that in your uart node:
usart3: serial#fc00c000 {
pinctrl-names = "default","gpio";
pinctrl-0 = <&pinctrl_usart3>;
pinctrl-1 = <&pinctrl_usart3_gpio>;
tx-gpio = <&pioE 4 GPIO_ACTIVE_LOW>;
status = "okay";
};
In the driver code:
pinctrl_pins_default = pinctrl_lookup_state(pinctrl, PINCTRL_STATE_DEFAULT);
pinctrl_pins_gpio = pinctrl_lookup_state(pinctrl, "gpio");
tx_gpio = of_get_named_gpio(pdev->dev.of_node, "tx-gpio", 0);
Then, you can use pinctrl_select_state to switch back and forth between pinctrl_pins_default and pinctrl_pins_gpio. tx_gpio is your gpio.

Related

How to make a linux driver detect and use a device after linux kernel has already loaded?

I am using a System Monitor device at address 0x3f on i2c-0 bus. This device is configured with the pmbus driver in the device tree.
The problem is that, this 'Sysmon' device is not powered when the linux kernel is loaded. Therefore, when I do a i2cdetect on bus 0 we see '--' at 0x3f which is expected. Now, when I power the Sysmon using my UI, the device is added by linux and we see a '3f' on running the i2cdetect.
Now, I want the pmbus driver to detect this device and change it to 'UU' so that I can see all the pmbus attributes in sysfs.
Can I do it from userspace and how? If no, can you suggest how can I tackle this.
If I force power the device using hardware and then load linux, the pmbus driver detects this device and reserves it. But I'm not allowed to force power the device.
Device Tree:
i2c#ff020000
{
compatible = "cdns,i2c-r1p14", "cdns,i2c-r1p10";
status = "okay";
interrupt-parent = <0x4>;
interrupts = <0x0 0x11 0x4>;
reg = <0x0 0xff020000 0x0 0x1000>;
#address-cells = <0x1>;
#size-cells = <0x0>;
power-domains = <0x15>;
clocks = <0x3 0x3d>;
clock-frequency = <0x186a0>;
pinctrl-names = "default", "gpio";
pinctrl-0 = <0x16>;
pinctrl-1 = <0x17>;
scl-gpios = <0x18 0x4a 0x0>;
sda-gpios = <0x18 0x4b 0x0>;
fpga1sysmon0#3f {
compatible = "general,pmbus";
reg = <0x3f>;
};
PS: I'm a beginner and this is my 1st question on Stack Overflow. Please bear with me for any mistakes I've made.
what about enabling the sysmon in /etc/init.d/rcS (assuming you are using busybox init) or in systemd /etc/rc.local.
the following will load the driver for an LTC2978 at address 0x60
on I2C bus #1:
$ modprobe pmbus
$ echo ltc2978 0x60 > /sys/bus/i2c/devices/i2c-1/new_device
you can put that in
/etc/init.d/rcS or /etc/rc.local
see also
https://www.kernel.org/doc/Documentation/hwmon/pmbus

Linux kernel does not see all components on my at91sam9g20 board

I am working with a Stamp9g20 embedded chip. It is based on the Atmel at91sam9g20 platform. For a client I need to upgrade the kernel to a newer version. After a bit of research, I landed on the Linux4SAM pages and their additional yocto layer, complete with a 4.14 kernel!
However, when I compile that kernel, I don't see all of my devices, for example, I can write onto the NAND memory and mount an USB device, but I cannot see nor mount any mmc/mci devices. I have tried checking how the Stamp9g20 really differs from the AT91SAM9G20EK, but I couldn't find a definitive clue to an answer there.
The Linux4SAM repo supports slightly different versions of the AT91SAM9 family, but I got it working for the 4.14 kernel, using the at91sam9g20ek.dts as an input for the board. Had to add my machine to the compatible machine list, so it will compile for the 9g20 versions as well.
COMPATIBLE_MACHINE += 'at91sam9g20ek'
and my machine.conf looks like:
##Name: ATMEL AT91SAM9G20EK
##DESCRIPTION: Machine configuration for Atmel's evaluation board
#
# define SOC_FAMILY (we are the family of ...)
SOC_FAMILY = "atsam9"
# Add arm926ejs to the DEFAULTTUNE, so it will be selected in our environment
DEFAULTTUNE = "arm926ejs"
# http://lists.openembedded.org/pipermail/openembedded-core/2019-January/277527.html
#TUNE_CCARGS .= "${#bb.utils.contains('TUNE_FEATURES', 'armv5', ' -march=armv5t${ARMPKGSFX_DSP}', '', d)}"
TUNE_CCARGS = "${#bb.utils.contains('TUNE_FEATURES', 'armv5', ' -march=armv5t${ARMPKGSFX_DSP}', '', d)}"
# We rely on the generic meta-atmel layer
require conf/machine/include/at91sam9.inc
MACHINE_FEATURES = "apm ext2 ext3 ext4 usbhost usbgadget vfat jffs2"
# This device tree is available in the kernel
KERNEL_DEVICETREE = " \
at91sam9g20ek.dtb \
"
# Create filesystems tar.gz and jffs2
IMAGE_FSTYPES += " tar.gz jffs2 tar"
# UNTESTED IMAGES (both bootstrap and uboot)
UBOOT_MACHINE ?= "at91sam9g20ek_nandflash_defconfig"
UBOOT_ENTRYPOINT = "0x20008000"
UBOOT_LOADADDRESS = "0x20008000"
AT91BOOTSTRAP_MACHINE ?= "at91sam9g20ek"
When the kernel launches, it shows that it registers a device driver onto the address 0xffff8000, but it doesn't see a block device.
bus: 'mmc': add driver mmcblk
bus: 'sdio': add driver sdio_uart
bus: 'platform': add driver atmel_mci
bus: 'platform': driver_probe_device: matched device fffa8000.mmc with driver atmel_mci
bus: 'platform': really_probe: probing driver atmel_mci with device fffa8000.mmc
atmel_mci fffa8000.mmc: no init pinctrl state
atmel_mci fffa8000.mmc: version: 0x210
atmel_mci fffa8000.mmc: using PDC
device: 'mmc0': device_add
atmel_mci fffa8000.mmc: Atmel MCI controller at 0xfffa8000 irq 30, 1 slots
driver: 'atmel_mci': driver_bound: bound to device 'fffa8000.mmc'
bus: 'platform': really_probe: bound device fffa8000.mmc to driver atmel_mci
I have tried this board with the 2.6.x version where it works as expected.
How can I make the block device mmcblk available in the system? Do I need to change the .dts (currently I am using the at91sam9g20ek.dts as a template with a minor change to the NAND memory). Or what can I do to get more information as to why the kernel doesn't interact with the mmc device?
Also, if I compare the source code from before the dts structure, I don't see significant differences in the mcc part of the code:
https://elixir.bootlin.com/linux/v3.6.9/source/arch/arm/mach-at91/board-sam9g20ek.c
https://elixir.bootlin.com/linux/v3.6.9/source/arch/arm/mach-at91/board-stamp9g20.c
The only difference I found,
at91sam9g20ek board:
.slot_b = 1, /* Only one slot so use slot B */
stamp9g20 board:
.slot_b = 0,
so I tried changing the reg<> property in the dts to 1, but to no avail...
Found it! All I had to do was change the mmc slot (was 1) in the dts to slot 0:
--- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
## -39,8 +39,8 ##
};
- mmc0_slot1 {
- pinctrl_board_mmc0_slot1: mmc0_slot1-board {
+ mmc0_slot0 {
+ pinctrl_board_mmc0_slot0: mmc0_slot0-board {
atmel,pins =
<AT91_PIOC 9 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>; /* PC9 gpio CD pin pull up and deglitch */
};
## -90,15 +90,14 ##
mmc0: mmc#fffa8000 {
pinctrl-0 = <
- &pinctrl_board_mmc0_slot1
+ &pinctrl_board_mmc0_slot0
&pinctrl_mmc0_clk
- &pinctrl_mmc0_slot1_cmd_dat0
- &pinctrl_mmc0_slot1_dat1_3>;
+ &pinctrl_mmc0_slot0_cmd_dat0
+ &pinctrl_mmc0_slot0_dat1_3>;
status = "okay";
- slot#1 {
- reg = <1>;
+ slot#0 {
+ reg = <0>;
bus-width = <4>;
- cd-gpios = <&pioC 9 GPIO_ACTIVE_HIGH>;
};
};

What causes "resource temporarily unavailable" in v4l2

I have compiled adv7180 driver available here.
I am unloading the ov5642 cameradriver(which in my case is built-in) and loading the adv7180_tvin module and after I am loading mxcv4l2_capture module which creates video0 in /dev/.
(dmesg command says: "mxc camera on IPU2_CSI1 registered as video0")
But when I try to access video0 with v4l2-ctl I got a message "resource temporarily unavailable" or when I am using gstreamer I got message "Can not open /dev/video0" (but the device is really created).
Is that a problem in device tree settings or it can be caused by something else? Which tools should I use to find out what causes this issue?
My device tree settings look like below:
&i2c3{
adv7180: adv7180#20{
compatible = "adv,adv7180";
reg = <0x20>;
clocks = <&clks IMX6QDL_CLK_CKO2>;
clock-names = "csi_mclk";
pwn-gpios = <&gpio3 10 GPIO_ACTIVE_LOW>;
ipu_id = <1>;
csi_id = <1>;
mclk = <24000000>;
mclk_source = <0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hummingboard2_parallel>;
cvbs = <1>;
};
};
I need to add that before adv7180 I was using above settings for ov5642 camera (excluding cvbs setting) and everything worked properly.
EDIT:
Ok I got one clue.
When I load modules in dmesg message "mxc_v4l2_master_attach: ipu(0:1)/csi(1:1)/mipi(0:0) doesn't match" shows.
But it only happens when ipu_id=<1> in v4l2_cap device tree settings and in adv7180 settings. When i change ipu_id to ipu_id=<0> in v4l2 settings and adv7180 dmesg now shows "parallel attach to IPU1 CSI1 and I can access the /dev/video0 succesfully with v4l2-ctl tool.
But In my case there is only one possibility to use IPU2_CSI1.
Why can't I set IPU2 to adv7180 when I was using it successfully to ov5642 ?
As per my knowledge i.MX6 having two IPUs. I think by default IPU1 parallel interface is not enabled in the board file. So you need to check the IOMUXC_GPR1 register setting (bit 19 and 20) for IPU/CSI1 and pass the csi_id in your camera driver.
As you are using the parallel interface so check your pin muxing setting as well in your device tree. (which is not required for serial interface.)
Edit:
There are two ways which you can follow to update the register setting from the kernel space (boardfile or camera driver) itself:
1. From the board file:
struct regmap *gpr
gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
regmap_update_bits(gpr, IOMUXC_GPR1, 1 << 20, 1 << 20);
2. From the boardfile or camera driver
void __iomem *va_ipu2_address;
u32 reg_val;
va_ipu2_address = ioremap(0x20e0004,0xe0004);
reg_val = readl(va_ipu2_address);
/* Enable parallel interface to IPU2 CSI1. */
writel(reg_val | 1 << 20, va_ipu2_address);
Thanks for Your answer.
My pinmuxing looks like this:
&iomuxc{
hummingboard2{
pinctrl_hummingboard2_parallel: hummingboard2_parallel{
fsl,pins = <
MX6QDL_PAD_EIM_A24__IPU2_CSI1_DATA19 0x0b0b1
MX6QDL_PAD_EIM_A23__IPU2_CSI1_DATA18 0x0b0b1
MX6QDL_PAD_EIM_A22__IPU2_CSI1_DATA17 0x0b0b1
MX6QDL_PAD_EIM_A21__IPU2_CSI1_DATA16 0x0b0b1
MX6QDL_PAD_EIM_A20__IPU2_CSI1_DATA15 0x0b0b1
MX6QDL_PAD_EIM_A19__IPU2_CSI1_DATA14 0x0b0b1
MX6QDL_PAD_EIM_A18__IPU2_CSI1_DATA13 0x0b0b1
MX6QDL_PAD_EIM_A17__IPU2_CSI1_DATA12 0x0b0b1
MX6QDL_PAD_EIM_DA11__IPU2_CSI1_HSYNC 0x0b0b1
MX6QDL_PAD_EIM_DA12__IPU2_CSI1_VSYNC 0x0b0b1
MX6QDL_PAD_EIM_A16__IPU2_CSI1_PIXCLK 0x0b0b1
MX6QDL_PAD_EIM_DA10__GPIO3_IO10 0x400130b1
>;
};
};
};
and it's been working succesively with ov5642 camera.
No I see that the adv7180 driver does not take an ipu_id as an argument from device tree so I think it is using the default ipu which is (I think) IPU1.
I've been playing arround how to change settings in IOMUXC_GPR1. Bit 20 needs to be set ("enable parallel interface to IPU2 CSI1). But have got no more ideas how to do it in device tree.
Ok. I found it !
I couldn't set bit 20 in IOMUXC_GPR1 register using mach-imx6q.c file so I did it this way:
in console:
sudo devmem2 0x20e0004
and read the existing value (which was in my case 0x48643005). Then I set bit 20 to one ("1") so I got 0x48743005 and I put this value into the register:
sudo devmem2 0x20e0004 w 0x48743005
next I loaded adv7180_tvin and mxc_v4l2_capture modules and captured frames using gsreamer:
gst-launch-1.0 imxv4l2videosrc device=/dev/video0 ! imxipuvideotransform ! autovideosink deinterlace=true
Everything works great ! Thanks for help !

trouble configuring timings for LVDS display (linux on rk3288)

I'm trying to hook up an LVDS display to my dev board based on rockchip rk3288 and have trouble getting graphics to show on the display.
The display is the GWTS80MNFG1E0 by SGD. The datasheet is here http://www.datadisplay-group.com/fileadmin/pdf/produkte/Displays/SGD/GWTS80MNFG1E0_Datasheet.pdf
Here is the .dtsi file I created for the display:
/ {
disp_timings: display-timings {
native-mode = <&timing0>;
timing0: timing0 {
screen-type = <SCREEN_LVDS>;
lvds-format = <LVDS_8BIT_1>;
out-face = <OUT_P888>;
clock-frequency = <48690000 52590000 60830000>;
hactive = <1656 1660 1760>;
vactive = <490 528 576>;
hback-porch = <5 16 141>;
hfront-porch = <19 44 155>;
vback-porch = <5 5 91>;
vfront-porch = <5 43 91>;
hsync-len = <1 2 140>;
vsync-len = <1 2 90>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <1>;
pixelclk-active = <0>;
swap-rb = <0>;
swap-rg = <0>;
swap-gb = <0>;
};
};
};
The problem is that the display turns on but I can't see any graphics. In the .config file for the kernel I have CONFIG_RK32_LVDS=y. The .dts file for the board includes my .dtsi file.
Hardware details:
On my breadboard, interfacing my dev board to the display, I've pulled STBYB, RESET, SELB, RL, and TB high via a 10k pullup to 3.3v.
For backlight I'm using the adafruit tft friend - https://www.adafruit.com/product/1932
I'm taking 5v from my dev board to feed the backlight driver and I've hooked up LED- and LED+ of the display to the backlight driver. The driver is configured to output 75mA at the moment. The adafruit board has specs of outputting up to 125mA at 24V while the SGD datasheet mentions 25.6V. I'm not sure if this is a problem or not.
I have the VSDN/VSDP hooked up to a TPS65132WEVM-669 (texas instruments) which I've programmed to provide +/- 5.5v. This EVM is powered from the same 5v as the backlight driver. I've verified it's outputting the correct voltages.
I've hooked up the display inputs RXIN[0123]+/- to board lvds port outputs D[0123]P/N. Display clock inputs RXCLKIN+/- are hooked up to board lvds port clock lines CLK0P/N.
My questions:
1) is the backlight driver the problem here?
2) is the .dtsi file I created for the display correct?
3) is there anything else I can check w/r/t my kernel / dts config or the hardware itself?
Thanks
B
There are five items which need to be verified:
LVDS settings in dts:
Check the IPU channel which is correctly mapped on the lvds device
data-width (18bit/24bit) of the lvds channel.
LVDS output format for serializer (VESA or Non-VESA format )
Frame buffer settings in dts:
Check your frame buffer settings
- bit pet pixels
- Pixel format
- ipu clock
Kernel command:
Check whether any of the kernel command which is overwrite the dtsi settings during kernel startup.
Backlight:
In order to make the backlight, measure the display current.
Lock:
Check the physical connection between serializer and deserializer. Make sure the LOCK signal.
I had as similar issue after a kernel update, and this kernel "fix" was the problem. Newer kernels (after 2013) fall back on not having any LVDS screen, which mean that you don't see any graphics.
http://marc.info/?l=git-commits-head&m=138449380916013&w=2

Specifying GPIO Numbers for IO Expander in Linux Device Tree

I'm trying to add a PCA9557 I/O expander to an arm-based system on an I2C bus. The system already has another I/O expander on a different I2C bus. I am trying to figure out how to specify which GPIO numbers the pins on the new expander get, and how to get both working.
Here's the device tree section for the existing expander, under I2C bus 2:
i2c2: i2c#e8007000 {
status = "ok";
pca9539: pca9539#74 {
compatible = "nxp,pca9539";
reg = <0x74>;
interrupt-parent = <&gpio>;
interrupts = <9 0x0>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
};
Using the above, the existing I/O expander (with 16 GPIOs) appears in linux as /sys/class/gpio/gpiochip128, exposing GPIO numbers 128 - 143. GPIOs 0-127 are built in to the host processor.
I added the following for the new expander on I2C bus 0:
i2c0: i2c#e8003000 {
status = "ok";
pca9557: pca9557#18 {
compatible = "nxp,pca9557";
reg = <0x18>;
gpio-controller;
#gpio-cells = <2>;
};
I also modified the kernel config to build the GPIO_PCA953X driver, which should support the PCA9557.
When I compile and boot with the above added to the device tree, I now see the NEW expander (PCA9557) mapped as /sys/class/gpio/gpiochip136, and it works (I can set its IO 0 pin using GPIO128).
However, there are no longer any GPIO pins for the other expander. It still appears as a device on the appropriate bus under /sys/devices/... but a directory listing doesn't show the "driver..." and "i2c-2" items which were there before.
So how do I get BOTH expanders to appear in /sys/class/gpio/ with different ranges of GPIO numbers, so I can use both?
I guess the "128" as the base GPIO for the original expander was just the next available GPIO? But why does the new expander end up starting at GPIO 136?
I've seen several references to this page: GPIO bindings documentation, but it was fairly generic and didn't help much.

Resources