MCP23017

Our hackerspace’s access-control-system (for unlocking the door) uses a few mcp23017 port expanders for input/output handling of different sensors and actors. When I started working on this, the mcp23s08 driver (which also supports the mcp23017) was not yet enabled in Debian’s arm build. I requested it to be enabled in Debian Bug #845064, which got recently fixed by Ben Hutchings. As a quick hack to solve the problem I took the driver and ripped it out of the kernel, so that I can build it externally. Fortunately all dependencies were available from Debian’s kernel.

$ uname -a Linux acs 4.8.0-1-armmp #1 SMP Debian 4.8.5-1 (2016-10-28) armv7l GNU/Linux $ sudo apt-get install build-essential linux-headers-4.8.0-1-armmp $ mkdir kernel-extra-module && cd kernel-extra-module $ cp ~/src/linux/drivers/gpio/gpio-mcp23s08.c . $ echo “obj-m += gpio-mcp23s08.o” >> Makefile $ make -C /lib/modules/uname -r/build M=$PWD $ make -C /lib/modules/uname -r/build M=$PWD modules_install $ sudo depmod

Unfortunately I was lazy while soldering the PCB and did not add 32 pull-up resistors. Instead I relied on the port-expander’s built-in ones. Later I noticed, that they are not supported by the kernel driver (there is non-standard support if its probed via boardcode, but RPi uses DT). Instead of fixing it properly I decided to add a quick hack enabling all pull-ups and taking care of a proper patch later.

In the meantime a nasty HW bug occured, which resulted in a short power-loss of the mcp23017. Dumping the register values would have helped to find the issue, so another patch for the mcp23s08 driver on my TODO list was regmap usage inside of the driver. Usage of regmap inside of the driver reduces lines of code and easy debugging via regmap’s debugfs interface:

acs# cat /sys/kernel/debug/regmap/1-0021/registers 00: fffe 02: 0000 04: fffc 06: 0000 08: 0000 0a: 4848 0c: ffff 0e: 0000 10: fff3 12: fff7 14: 0101

I finally got around to do the necessary changes and sent them out, you can find the result here: https://lkml.org/lkml/2017/1/27/530

The DT snippet from below can be used to register the kernel driver with pull-ups enabled on all pins and single IRQ connected to gpio 23 from the SoC.

&i2c { i2cgpio0: gpio@21 { compatible = “microchip,mcp23017”; gpio-controller; #gpio-cells = <0x2>; reg = <0x21>; interrupt-parent = <&socgpio>; interrupts = <0x17 0x8>; interrupt-controller; #interrupt-cells = <0x2>; microchip,irq-mirror; pinctrl-names = “default”; pinctrl-0 = <&i2cgpio0irq &gpio21_pullups>; gpio21_pullups: pinmux { pins = “gpio0”, “gpio1”, “gpio2”, “gpio3”, “gpio4”, “gpio5”, “gpio6”, “gpio7”, “gpio8”, “gpio9”, “gpio10”, “gpio11”, “gpio12”, “gpio13”, “gpio14”, “gpio15”; bias-pull-up; }; }; };