Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM/mfd/gpio: Fixup TPS65010 regression on OMAP1 OSK1

Aaro reports problems on the OSK1 board after we altered
the dynamic base for GPIO allocations.

It appears this happens because the OMAP driver now
allocates GPIO numbers dynamically, so all that is
references by number is a bit up in the air.

Let's bite the bullet and try to just move the gpio_chip
in the tps65010 MFD driver over to using dynamic allocations.
Alter everything in the OSK1 board file to use a GPIO
descriptor table and lookups.

Utilize the NULL device to define some board-specific
GPIO lookups and use these to immediately look up the
same GPIOs, convert to IRQ numbers and pass as resources
to the devices. This is ugly but should work.

The .setup() callback for tps65010 was used for some GPIO
hogging, but since the OSK1 is the only user in the entire
kernel we can alter the signatures to something that
is helpful and make a clean transition.

Fixes: 92bf78b33b0b ("gpio: omap: use dynamic allocation of base")
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: andy.shevchenko@gmail.com
Cc: Andreas Kemnade <andreas@kemnade.info>
Acked-by: Lee Jones <lee@kernel.org>
Reviewed-by: Lee Jones <lee@kernel.org>
Reported-by: Aaro Koskinen <aaro.koskinen@iki.fi>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

+104 -60
+95 -44
arch/arm/mach-omap1/board-osk.c
··· 25 25 * with this program; if not, write to the Free Software Foundation, Inc., 26 26 * 675 Mass Ave, Cambridge, MA 02139, USA. 27 27 */ 28 - #include <linux/gpio.h> 28 + #include <linux/gpio/consumer.h> 29 + #include <linux/gpio/driver.h> 29 30 #include <linux/gpio/machine.h> 30 31 #include <linux/kernel.h> 31 32 #include <linux/init.h> ··· 65 64 /* TPS65010 has four GPIOs. nPG and LED2 can be treated like GPIOs with 66 65 * alternate pin configurations for hardware-controlled blinking. 67 66 */ 68 - #define OSK_TPS_GPIO_BASE (OMAP_MAX_GPIO_LINES + 16 /* MPUIO */) 69 - # define OSK_TPS_GPIO_USB_PWR_EN (OSK_TPS_GPIO_BASE + 0) 70 - # define OSK_TPS_GPIO_LED_D3 (OSK_TPS_GPIO_BASE + 1) 71 - # define OSK_TPS_GPIO_LAN_RESET (OSK_TPS_GPIO_BASE + 2) 72 - # define OSK_TPS_GPIO_DSP_PWR_EN (OSK_TPS_GPIO_BASE + 3) 73 - # define OSK_TPS_GPIO_LED_D9 (OSK_TPS_GPIO_BASE + 4) 74 - # define OSK_TPS_GPIO_LED_D2 (OSK_TPS_GPIO_BASE + 5) 67 + #define OSK_TPS_GPIO_USB_PWR_EN 0 68 + #define OSK_TPS_GPIO_LED_D3 1 69 + #define OSK_TPS_GPIO_LAN_RESET 2 70 + #define OSK_TPS_GPIO_DSP_PWR_EN 3 71 + #define OSK_TPS_GPIO_LED_D9 4 72 + #define OSK_TPS_GPIO_LED_D2 5 75 73 76 74 static struct mtd_partition osk_partitions[] = { 77 75 /* bootloader (U-Boot, etc) in first sector */ ··· 174 174 /* NOTE: D9 and D2 have hardware blink support. 175 175 * Also, D9 requires non-battery power. 176 176 */ 177 - { .gpio = OSK_TPS_GPIO_LED_D9, .name = "d9", 178 - .default_trigger = "disk-activity", }, 179 - { .gpio = OSK_TPS_GPIO_LED_D2, .name = "d2", }, 180 - { .gpio = OSK_TPS_GPIO_LED_D3, .name = "d3", .active_low = 1, 181 - .default_trigger = "heartbeat", }, 177 + { .name = "d9", .default_trigger = "disk-activity", }, 178 + { .name = "d2", }, 179 + { .name = "d3", .default_trigger = "heartbeat", }, 180 + }; 181 + 182 + static struct gpiod_lookup_table tps_leds_gpio_table = { 183 + .dev_id = "leds-gpio", 184 + .table = { 185 + /* Use local offsets on TPS65010 */ 186 + GPIO_LOOKUP_IDX("tps65010", OSK_TPS_GPIO_LED_D9, NULL, 0, GPIO_ACTIVE_HIGH), 187 + GPIO_LOOKUP_IDX("tps65010", OSK_TPS_GPIO_LED_D2, NULL, 1, GPIO_ACTIVE_HIGH), 188 + GPIO_LOOKUP_IDX("tps65010", OSK_TPS_GPIO_LED_D3, NULL, 2, GPIO_ACTIVE_LOW), 189 + { } 190 + }, 182 191 }; 183 192 184 193 static struct gpio_led_platform_data tps_leds_data = { ··· 201 192 .dev.platform_data = &tps_leds_data, 202 193 }; 203 194 204 - static int osk_tps_setup(struct i2c_client *client, void *context) 195 + /* The board just hold these GPIOs hogged from setup to teardown */ 196 + static struct gpio_desc *eth_reset; 197 + static struct gpio_desc *vdd_dsp; 198 + 199 + static int osk_tps_setup(struct i2c_client *client, struct gpio_chip *gc) 205 200 { 201 + struct gpio_desc *d; 206 202 if (!IS_BUILTIN(CONFIG_TPS65010)) 207 203 return -ENOSYS; 208 204 209 205 /* Set GPIO 1 HIGH to disable VBUS power supply; 210 206 * OHCI driver powers it up/down as needed. 211 207 */ 212 - gpio_request(OSK_TPS_GPIO_USB_PWR_EN, "n_vbus_en"); 213 - gpio_direction_output(OSK_TPS_GPIO_USB_PWR_EN, 1); 208 + d = gpiochip_request_own_desc(gc, OSK_TPS_GPIO_USB_PWR_EN, "n_vbus_en", 209 + GPIO_ACTIVE_HIGH, GPIOD_OUT_HIGH); 214 210 /* Free the GPIO again as the driver will request it */ 215 - gpio_free(OSK_TPS_GPIO_USB_PWR_EN); 211 + gpiochip_free_own_desc(d); 216 212 217 213 /* Set GPIO 2 high so LED D3 is off by default */ 218 214 tps65010_set_gpio_out_value(GPIO2, HIGH); 219 215 220 216 /* Set GPIO 3 low to take ethernet out of reset */ 221 - gpio_request(OSK_TPS_GPIO_LAN_RESET, "smc_reset"); 222 - gpio_direction_output(OSK_TPS_GPIO_LAN_RESET, 0); 217 + eth_reset = gpiochip_request_own_desc(gc, OSK_TPS_GPIO_LAN_RESET, "smc_reset", 218 + GPIO_ACTIVE_HIGH, GPIOD_OUT_LOW); 223 219 224 220 /* GPIO4 is VDD_DSP */ 225 - gpio_request(OSK_TPS_GPIO_DSP_PWR_EN, "dsp_power"); 226 - gpio_direction_output(OSK_TPS_GPIO_DSP_PWR_EN, 1); 221 + vdd_dsp = gpiochip_request_own_desc(gc, OSK_TPS_GPIO_DSP_PWR_EN, "dsp_power", 222 + GPIO_ACTIVE_HIGH, GPIOD_OUT_HIGH); 227 223 /* REVISIT if DSP support isn't configured, power it off ... */ 228 224 229 225 /* Let LED1 (D9) blink; leds-gpio may override it */ ··· 246 232 247 233 /* register these three LEDs */ 248 234 osk5912_tps_leds.dev.parent = &client->dev; 235 + gpiod_add_lookup_table(&tps_leds_gpio_table); 249 236 platform_device_register(&osk5912_tps_leds); 250 237 251 238 return 0; 252 239 } 253 240 241 + static void osk_tps_teardown(struct i2c_client *client, struct gpio_chip *gc) 242 + { 243 + gpiochip_free_own_desc(eth_reset); 244 + gpiochip_free_own_desc(vdd_dsp); 245 + } 246 + 254 247 static struct tps65010_board tps_board = { 255 - .base = OSK_TPS_GPIO_BASE, 256 248 .outmask = 0x0f, 257 249 .setup = osk_tps_setup, 250 + .teardown = osk_tps_teardown, 258 251 }; 259 252 260 253 static struct i2c_board_info __initdata osk_i2c_board_info[] = { ··· 284 263 { 285 264 u32 l; 286 265 287 - if ((gpio_request(0, "smc_irq")) < 0) { 288 - printk("Error requesting gpio 0 for smc91x irq\n"); 289 - return; 290 - } 291 - 292 266 /* Check EMIFS wait states to fix errors with SMC_GET_PKT_HDR */ 293 267 l = omap_readl(EMIFS_CCS(1)); 294 268 l |= 0x3; ··· 295 279 struct resource *res = &osk5912_cf_resources[1]; 296 280 297 281 omap_cfg_reg(M7_1610_GPIO62); 298 - if ((gpio_request(62, "cf_irq")) < 0) { 299 - printk("Error requesting gpio 62 for CF irq\n"); 300 - return; 301 - } 302 282 303 283 switch (seg) { 304 284 /* NOTE: CS0 could be configured too ... */ ··· 320 308 seg, omap_readl(EMIFS_CCS(seg)), omap_readl(EMIFS_ACS(seg))); 321 309 omap_writel(0x0004a1b3, EMIFS_CCS(seg)); /* synch mode 4 etc */ 322 310 omap_writel(0x00000000, EMIFS_ACS(seg)); /* OE hold/setup */ 323 - 324 - /* the CF I/O IRQ is really active-low */ 325 - irq_set_irq_type(gpio_to_irq(62), IRQ_TYPE_EDGE_FALLING); 326 311 } 327 312 328 313 static struct gpiod_lookup_table osk_usb_gpio_table = { 329 314 .dev_id = "ohci", 330 315 .table = { 331 316 /* Power GPIO on the I2C-attached TPS65010 */ 332 - GPIO_LOOKUP("tps65010", 0, "power", GPIO_ACTIVE_HIGH), 317 + GPIO_LOOKUP("tps65010", OSK_TPS_GPIO_USB_PWR_EN, "power", 318 + GPIO_ACTIVE_HIGH), 333 319 GPIO_LOOKUP(OMAP_GPIO_LABEL, 9, "overcurrent", 334 320 GPIO_ACTIVE_HIGH), 321 + { } 335 322 }, 336 323 }; 337 324 ··· 352 341 353 342 #define EMIFS_CS3_VAL (0x88013141) 354 343 344 + static struct gpiod_lookup_table osk_irq_gpio_table = { 345 + .dev_id = NULL, 346 + .table = { 347 + /* GPIO used for SMC91x IRQ */ 348 + GPIO_LOOKUP(OMAP_GPIO_LABEL, 0, "smc_irq", 349 + GPIO_ACTIVE_HIGH), 350 + /* GPIO used for CF IRQ */ 351 + GPIO_LOOKUP("gpio-48-63", 14, "cf_irq", 352 + GPIO_ACTIVE_HIGH), 353 + /* GPIO used by the TPS65010 chip */ 354 + GPIO_LOOKUP("mpuio", 1, "tps65010", 355 + GPIO_ACTIVE_HIGH), 356 + { } 357 + }, 358 + }; 359 + 355 360 static void __init osk_init(void) 356 361 { 362 + struct gpio_desc *d; 357 363 u32 l; 358 364 359 365 osk_init_smc91x(); ··· 387 359 388 360 osk_flash_resource.end = osk_flash_resource.start = omap_cs3_phys(); 389 361 osk_flash_resource.end += SZ_32M - 1; 390 - osk5912_smc91x_resources[1].start = gpio_to_irq(0); 391 - osk5912_smc91x_resources[1].end = gpio_to_irq(0); 392 - osk5912_cf_resources[0].start = gpio_to_irq(62); 393 - osk5912_cf_resources[0].end = gpio_to_irq(62); 362 + 363 + /* 364 + * Add the GPIOs to be used as IRQs and immediately look them up 365 + * to be passed as an IRQ resource. This is ugly but should work 366 + * until the day we convert to device tree. 367 + */ 368 + gpiod_add_lookup_table(&osk_irq_gpio_table); 369 + 370 + d = gpiod_get(NULL, "smc_irq", GPIOD_IN); 371 + if (IS_ERR(d)) { 372 + pr_err("Unable to get SMC IRQ GPIO descriptor\n"); 373 + } else { 374 + irq_set_irq_type(gpiod_to_irq(d), IRQ_TYPE_EDGE_RISING); 375 + osk5912_smc91x_resources[1] = DEFINE_RES_IRQ(gpiod_to_irq(d)); 376 + } 377 + 378 + d = gpiod_get(NULL, "cf_irq", GPIOD_IN); 379 + if (IS_ERR(d)) { 380 + pr_err("Unable to get CF IRQ GPIO descriptor\n"); 381 + } else { 382 + /* the CF I/O IRQ is really active-low */ 383 + irq_set_irq_type(gpiod_to_irq(d), IRQ_TYPE_EDGE_FALLING); 384 + osk5912_cf_resources[0] = DEFINE_RES_IRQ(gpiod_to_irq(d)); 385 + } 386 + 394 387 platform_add_devices(osk5912_devices, ARRAY_SIZE(osk5912_devices)); 395 388 396 389 l = omap_readl(USB_TRANSCEIVER_CTRL); ··· 421 372 gpiod_add_lookup_table(&osk_usb_gpio_table); 422 373 omap1_usb_init(&osk_usb_config); 423 374 375 + omap_serial_init(); 376 + 424 377 /* irq for tps65010 chip */ 425 378 /* bootloader effectively does: omap_cfg_reg(U19_1610_MPUIO1); */ 426 - if (gpio_request(OMAP_MPUIO(1), "tps65010") == 0) 427 - gpio_direction_input(OMAP_MPUIO(1)); 428 - 429 - omap_serial_init(); 430 - osk_i2c_board_info[0].irq = gpio_to_irq(OMAP_MPUIO(1)); 379 + d = gpiod_get(NULL, "tps65010", GPIOD_IN); 380 + if (IS_ERR(d)) 381 + pr_err("Unable to get TPS65010 IRQ GPIO descriptor\n"); 382 + else 383 + osk_i2c_board_info[0].irq = gpiod_to_irq(d); 431 384 omap_register_i2c_bus(1, 400, osk_i2c_board_info, 432 385 ARRAY_SIZE(osk_i2c_board_info)); 433 386 }
+5 -9
drivers/mfd/tps65010.c
··· 506 506 struct tps65010 *tps = i2c_get_clientdata(client); 507 507 struct tps65010_board *board = dev_get_platdata(&client->dev); 508 508 509 - if (board && board->teardown) { 510 - int status = board->teardown(client, board->context); 511 - if (status < 0) 512 - dev_dbg(&client->dev, "board %s %s err %d\n", 513 - "teardown", client->name, status); 514 - } 509 + if (board && board->teardown) 510 + board->teardown(client, &tps->chip); 515 511 if (client->irq > 0) 516 512 free_irq(client->irq, tps); 517 513 cancel_delayed_work_sync(&tps->work); ··· 615 619 tps, DEBUG_FOPS); 616 620 617 621 /* optionally register GPIOs */ 618 - if (board && board->base != 0) { 622 + if (board) { 619 623 tps->outmask = board->outmask; 620 624 621 625 tps->chip.label = client->name; ··· 628 632 /* NOTE: only partial support for inputs; nyet IRQs */ 629 633 tps->chip.get = tps65010_gpio_get; 630 634 631 - tps->chip.base = board->base; 635 + tps->chip.base = -1; 632 636 tps->chip.ngpio = 7; 633 637 tps->chip.can_sleep = 1; 634 638 ··· 637 641 dev_err(&client->dev, "can't add gpiochip, err %d\n", 638 642 status); 639 643 else if (board->setup) { 640 - status = board->setup(client, board->context); 644 + status = board->setup(client, &tps->chip); 641 645 if (status < 0) { 642 646 dev_dbg(&client->dev, 643 647 "board %s %s err %d\n",
+4 -7
include/linux/mfd/tps65010.h
··· 28 28 #ifndef __LINUX_I2C_TPS65010_H 29 29 #define __LINUX_I2C_TPS65010_H 30 30 31 + struct gpio_chip; 32 + 31 33 /* 32 34 * ---------------------------------------------------------------------------- 33 35 * Registers, all 8 bits ··· 178 176 179 177 /** 180 178 * struct tps65010_board - packages GPIO and LED lines 181 - * @base: the GPIO number to assign to GPIO-1 182 179 * @outmask: bit (N-1) is set to allow GPIO-N to be used as an 183 180 * (open drain) output 184 181 * @setup: optional callback issued once the GPIOs are valid 185 182 * @teardown: optional callback issued before the GPIOs are invalidated 186 - * @context: optional parameter passed to setup() and teardown() 187 183 * 188 184 * Board data may be used to package the GPIO (and LED) lines for use 189 185 * in by the generic GPIO and LED frameworks. The first four GPIOs ··· 193 193 * devices in their initial states using these GPIOs. 194 194 */ 195 195 struct tps65010_board { 196 - int base; 197 196 unsigned outmask; 198 - 199 - int (*setup)(struct i2c_client *client, void *context); 200 - int (*teardown)(struct i2c_client *client, void *context); 201 - void *context; 197 + int (*setup)(struct i2c_client *client, struct gpio_chip *gc); 198 + void (*teardown)(struct i2c_client *client, struct gpio_chip *gc); 202 199 }; 203 200 204 201 #endif /* __LINUX_I2C_TPS65010_H */