What exactly am I getting by adding entries of the form “ti,hwmods = “ in the device tree? Does anyone have a reference on how the TI hwmod system works? arch/arm/mach-omap2/omap_hwmod.c has a nice introduction, but it’s limited
The rest of this post is FYI on how I got the GPIO to work on the AM437X. The main “got ya” was that using “ti,hwmods = gpio6” in the dts causes the gpio module’s clocks to be initially disabled, and you have to enable them before you can write to the gpio modules registers.
I wanted to use GPIO5 for controlling LEDs from kernel and user space. The starting point is the gpio5 device tree entry in the AM437x eval board file arch/arm/boot/dts/am4372.dtsi.
gpio5: gpio@48322000 {
compatible = "ti,am4372-gpio","ti,omap4-gpio";
reg = <0x48322000 0x1000>;
interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
ti,hwmods = "gpio6";
status = "disabled";
};
This file is included in my custom dts along with the entry
&gpio5 {
status = "okay";
};
My kernel module uses the standard technique of requesting and mapping io memory:
MemoryRegion = request_mem_region(physicalAddr, length);
VirtualAddr = ioremap(physicalAddr,length);
and the user application (which does not require my kernel module) uses the Linux /dev/mem driver and mmap
fd=open(“/dev/mem”,O_RDWR | O_SYNC);
VirtualAddr = mmap(0,size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, physicalAddr);
Note that the physical address must be page aligned. Corbet, et. al.,Linux Device Drivers explain these in detail.
Gpio can also be accessed through the sysfs as explained in Documentation/gpio-legacy.txt. The confusing part is finding the gpio number. Here is a simple way to find the number. Do a ls –l in the /sys/class/gpio directory. In my case I see the link in the output
gpiochip64 -> ../../devices/platform/44000000.ocp/4832200.gpio/gpio/gpiochip64
The thing to note is the 4832200 which corresponds to the device tree entry above for gpio5. So the gpio5 pins are handled by gpiochip64. The “64” is the Linux gpio number for the first pin handed by gpiochip64. Therefore, gpio5_0 is Linux gpio number 64 (gpio5_1 is 65, etc). To use the sysfs to access gpio5_0,
cd /sys/class/gpio
echo 64 > export
This creates the subdirectory /sys/class/gpio/gpio64, then
cd gpio64
echo out > direction
echo 0 > value
This makes Linux gpio 64, which is gpio5_0, an output and assigns it the value 0.
Here’s what I found. Both my kernel module and user application caused an exception (the dreaded Custom Error: MASTER M2) unless I removed the “ti,hwmods = gpio6” from the device tree, or unless I accessed the gpio using the sysfs before loading the kernel module or running the application. This was because the hwmod initialization left the gpio5 module’s clock disabled. The sysfs access enables the clock, so after using it, everything worked.
The solution is to enable the gpio module’s clock in the kernel module and user application BEFORE trying to access any of the gpio modules registers. So I needed to map two memory regions: first the CM_PER region in L4WKUP memory to access the gpio5 clock control register (CM_PER is for gpio1-5, for gpio0, it’s the CM_WKUP region), then, after enabling the clock, map the GPIO5 device in L4_PER memory (or for gpio0, map GPIO0 in L4_WKUP). Once these regions were mapped and I had virtual addresses for the registers, I configured them as described in the TRM and everything worked.