Skip to content

Commit c32c81f

Browse files
author
Linus Walleij
committed
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: 92bf78b ("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>
1 parent ac9a786 commit c32c81f

3 files changed

Lines changed: 104 additions & 60 deletions

File tree

arch/arm/mach-omap1/board-osk.c

Lines changed: 95 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
* with this program; if not, write to the Free Software Foundation, Inc.,
2626
* 675 Mass Ave, Cambridge, MA 02139, USA.
2727
*/
28-
#include <linux/gpio.h>
28+
#include <linux/gpio/consumer.h>
29+
#include <linux/gpio/driver.h>
2930
#include <linux/gpio/machine.h>
3031
#include <linux/kernel.h>
3132
#include <linux/init.h>
@@ -64,13 +65,12 @@
6465
/* TPS65010 has four GPIOs. nPG and LED2 can be treated like GPIOs with
6566
* alternate pin configurations for hardware-controlled blinking.
6667
*/
67-
#define OSK_TPS_GPIO_BASE (OMAP_MAX_GPIO_LINES + 16 /* MPUIO */)
68-
# define OSK_TPS_GPIO_USB_PWR_EN (OSK_TPS_GPIO_BASE + 0)
69-
# define OSK_TPS_GPIO_LED_D3 (OSK_TPS_GPIO_BASE + 1)
70-
# define OSK_TPS_GPIO_LAN_RESET (OSK_TPS_GPIO_BASE + 2)
71-
# define OSK_TPS_GPIO_DSP_PWR_EN (OSK_TPS_GPIO_BASE + 3)
72-
# define OSK_TPS_GPIO_LED_D9 (OSK_TPS_GPIO_BASE + 4)
73-
# define OSK_TPS_GPIO_LED_D2 (OSK_TPS_GPIO_BASE + 5)
68+
#define OSK_TPS_GPIO_USB_PWR_EN 0
69+
#define OSK_TPS_GPIO_LED_D3 1
70+
#define OSK_TPS_GPIO_LAN_RESET 2
71+
#define OSK_TPS_GPIO_DSP_PWR_EN 3
72+
#define OSK_TPS_GPIO_LED_D9 4
73+
#define OSK_TPS_GPIO_LED_D2 5
7474

7575
static struct mtd_partition osk_partitions[] = {
7676
/* bootloader (U-Boot, etc) in first sector */
@@ -174,11 +174,20 @@ static const struct gpio_led tps_leds[] = {
174174
/* NOTE: D9 and D2 have hardware blink support.
175175
* Also, D9 requires non-battery power.
176176
*/
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+
},
182191
};
183192

184193
static struct gpio_led_platform_data tps_leds_data = {
@@ -192,29 +201,34 @@ static struct platform_device osk5912_tps_leds = {
192201
.dev.platform_data = &tps_leds_data,
193202
};
194203

195-
static int osk_tps_setup(struct i2c_client *client, void *context)
204+
/* The board just hold these GPIOs hogged from setup to teardown */
205+
static struct gpio_desc *eth_reset;
206+
static struct gpio_desc *vdd_dsp;
207+
208+
static int osk_tps_setup(struct i2c_client *client, struct gpio_chip *gc)
196209
{
210+
struct gpio_desc *d;
197211
if (!IS_BUILTIN(CONFIG_TPS65010))
198212
return -ENOSYS;
199213

200214
/* Set GPIO 1 HIGH to disable VBUS power supply;
201215
* OHCI driver powers it up/down as needed.
202216
*/
203-
gpio_request(OSK_TPS_GPIO_USB_PWR_EN, "n_vbus_en");
204-
gpio_direction_output(OSK_TPS_GPIO_USB_PWR_EN, 1);
217+
d = gpiochip_request_own_desc(gc, OSK_TPS_GPIO_USB_PWR_EN, "n_vbus_en",
218+
GPIO_ACTIVE_HIGH, GPIOD_OUT_HIGH);
205219
/* Free the GPIO again as the driver will request it */
206-
gpio_free(OSK_TPS_GPIO_USB_PWR_EN);
220+
gpiochip_free_own_desc(d);
207221

208222
/* Set GPIO 2 high so LED D3 is off by default */
209223
tps65010_set_gpio_out_value(GPIO2, HIGH);
210224

211225
/* Set GPIO 3 low to take ethernet out of reset */
212-
gpio_request(OSK_TPS_GPIO_LAN_RESET, "smc_reset");
213-
gpio_direction_output(OSK_TPS_GPIO_LAN_RESET, 0);
226+
eth_reset = gpiochip_request_own_desc(gc, OSK_TPS_GPIO_LAN_RESET, "smc_reset",
227+
GPIO_ACTIVE_HIGH, GPIOD_OUT_LOW);
214228

215229
/* GPIO4 is VDD_DSP */
216-
gpio_request(OSK_TPS_GPIO_DSP_PWR_EN, "dsp_power");
217-
gpio_direction_output(OSK_TPS_GPIO_DSP_PWR_EN, 1);
230+
vdd_dsp = gpiochip_request_own_desc(gc, OSK_TPS_GPIO_DSP_PWR_EN, "dsp_power",
231+
GPIO_ACTIVE_HIGH, GPIOD_OUT_HIGH);
218232
/* REVISIT if DSP support isn't configured, power it off ... */
219233

220234
/* Let LED1 (D9) blink; leds-gpio may override it */
@@ -232,15 +246,22 @@ static int osk_tps_setup(struct i2c_client *client, void *context)
232246

233247
/* register these three LEDs */
234248
osk5912_tps_leds.dev.parent = &client->dev;
249+
gpiod_add_lookup_table(&tps_leds_gpio_table);
235250
platform_device_register(&osk5912_tps_leds);
236251

237252
return 0;
238253
}
239254

255+
static void osk_tps_teardown(struct i2c_client *client, struct gpio_chip *gc)
256+
{
257+
gpiochip_free_own_desc(eth_reset);
258+
gpiochip_free_own_desc(vdd_dsp);
259+
}
260+
240261
static struct tps65010_board tps_board = {
241-
.base = OSK_TPS_GPIO_BASE,
242262
.outmask = 0x0f,
243263
.setup = osk_tps_setup,
264+
.teardown = osk_tps_teardown,
244265
};
245266

246267
static struct i2c_board_info __initdata osk_i2c_board_info[] = {
@@ -263,11 +284,6 @@ static void __init osk_init_smc91x(void)
263284
{
264285
u32 l;
265286

266-
if ((gpio_request(0, "smc_irq")) < 0) {
267-
printk("Error requesting gpio 0 for smc91x irq\n");
268-
return;
269-
}
270-
271287
/* Check EMIFS wait states to fix errors with SMC_GET_PKT_HDR */
272288
l = omap_readl(EMIFS_CCS(1));
273289
l |= 0x3;
@@ -279,10 +295,6 @@ static void __init osk_init_cf(int seg)
279295
struct resource *res = &osk5912_cf_resources[1];
280296

281297
omap_cfg_reg(M7_1610_GPIO62);
282-
if ((gpio_request(62, "cf_irq")) < 0) {
283-
printk("Error requesting gpio 62 for CF irq\n");
284-
return;
285-
}
286298

287299
switch (seg) {
288300
/* NOTE: CS0 could be configured too ... */
@@ -308,18 +320,17 @@ static void __init osk_init_cf(int seg)
308320
seg, omap_readl(EMIFS_CCS(seg)), omap_readl(EMIFS_ACS(seg)));
309321
omap_writel(0x0004a1b3, EMIFS_CCS(seg)); /* synch mode 4 etc */
310322
omap_writel(0x00000000, EMIFS_ACS(seg)); /* OE hold/setup */
311-
312-
/* the CF I/O IRQ is really active-low */
313-
irq_set_irq_type(gpio_to_irq(62), IRQ_TYPE_EDGE_FALLING);
314323
}
315324

316325
static struct gpiod_lookup_table osk_usb_gpio_table = {
317326
.dev_id = "ohci",
318327
.table = {
319328
/* Power GPIO on the I2C-attached TPS65010 */
320-
GPIO_LOOKUP("tps65010", 0, "power", GPIO_ACTIVE_HIGH),
329+
GPIO_LOOKUP("tps65010", OSK_TPS_GPIO_USB_PWR_EN, "power",
330+
GPIO_ACTIVE_HIGH),
321331
GPIO_LOOKUP(OMAP_GPIO_LABEL, 9, "overcurrent",
322332
GPIO_ACTIVE_HIGH),
333+
{ }
323334
},
324335
};
325336

@@ -341,8 +352,25 @@ static struct omap_usb_config osk_usb_config __initdata = {
341352

342353
#define EMIFS_CS3_VAL (0x88013141)
343354

355+
static struct gpiod_lookup_table osk_irq_gpio_table = {
356+
.dev_id = NULL,
357+
.table = {
358+
/* GPIO used for SMC91x IRQ */
359+
GPIO_LOOKUP(OMAP_GPIO_LABEL, 0, "smc_irq",
360+
GPIO_ACTIVE_HIGH),
361+
/* GPIO used for CF IRQ */
362+
GPIO_LOOKUP("gpio-48-63", 14, "cf_irq",
363+
GPIO_ACTIVE_HIGH),
364+
/* GPIO used by the TPS65010 chip */
365+
GPIO_LOOKUP("mpuio", 1, "tps65010",
366+
GPIO_ACTIVE_HIGH),
367+
{ }
368+
},
369+
};
370+
344371
static void __init osk_init(void)
345372
{
373+
struct gpio_desc *d;
346374
u32 l;
347375

348376
osk_init_smc91x();
@@ -359,10 +387,31 @@ static void __init osk_init(void)
359387

360388
osk_flash_resource.end = osk_flash_resource.start = omap_cs3_phys();
361389
osk_flash_resource.end += SZ_32M - 1;
362-
osk5912_smc91x_resources[1].start = gpio_to_irq(0);
363-
osk5912_smc91x_resources[1].end = gpio_to_irq(0);
364-
osk5912_cf_resources[0].start = gpio_to_irq(62);
365-
osk5912_cf_resources[0].end = gpio_to_irq(62);
390+
391+
/*
392+
* Add the GPIOs to be used as IRQs and immediately look them up
393+
* to be passed as an IRQ resource. This is ugly but should work
394+
* until the day we convert to device tree.
395+
*/
396+
gpiod_add_lookup_table(&osk_irq_gpio_table);
397+
398+
d = gpiod_get(NULL, "smc_irq", GPIOD_IN);
399+
if (IS_ERR(d)) {
400+
pr_err("Unable to get SMC IRQ GPIO descriptor\n");
401+
} else {
402+
irq_set_irq_type(gpiod_to_irq(d), IRQ_TYPE_EDGE_RISING);
403+
osk5912_smc91x_resources[1] = DEFINE_RES_IRQ(gpiod_to_irq(d));
404+
}
405+
406+
d = gpiod_get(NULL, "cf_irq", GPIOD_IN);
407+
if (IS_ERR(d)) {
408+
pr_err("Unable to get CF IRQ GPIO descriptor\n");
409+
} else {
410+
/* the CF I/O IRQ is really active-low */
411+
irq_set_irq_type(gpiod_to_irq(d), IRQ_TYPE_EDGE_FALLING);
412+
osk5912_cf_resources[0] = DEFINE_RES_IRQ(gpiod_to_irq(d));
413+
}
414+
366415
platform_add_devices(osk5912_devices, ARRAY_SIZE(osk5912_devices));
367416

368417
l = omap_readl(USB_TRANSCEIVER_CTRL);
@@ -372,13 +421,15 @@ static void __init osk_init(void)
372421
gpiod_add_lookup_table(&osk_usb_gpio_table);
373422
omap1_usb_init(&osk_usb_config);
374423

424+
omap_serial_init();
425+
375426
/* irq for tps65010 chip */
376427
/* bootloader effectively does: omap_cfg_reg(U19_1610_MPUIO1); */
377-
if (gpio_request(OMAP_MPUIO(1), "tps65010") == 0)
378-
gpio_direction_input(OMAP_MPUIO(1));
379-
380-
omap_serial_init();
381-
osk_i2c_board_info[0].irq = gpio_to_irq(OMAP_MPUIO(1));
428+
d = gpiod_get(NULL, "tps65010", GPIOD_IN);
429+
if (IS_ERR(d))
430+
pr_err("Unable to get TPS65010 IRQ GPIO descriptor\n");
431+
else
432+
osk_i2c_board_info[0].irq = gpiod_to_irq(d);
382433
omap_register_i2c_bus(1, 400, osk_i2c_board_info,
383434
ARRAY_SIZE(osk_i2c_board_info));
384435
}

drivers/mfd/tps65010.c

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -506,12 +506,8 @@ static void tps65010_remove(struct i2c_client *client)
506506
struct tps65010 *tps = i2c_get_clientdata(client);
507507
struct tps65010_board *board = dev_get_platdata(&client->dev);
508508

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);
515511
if (client->irq > 0)
516512
free_irq(client->irq, tps);
517513
cancel_delayed_work_sync(&tps->work);
@@ -619,7 +615,7 @@ static int tps65010_probe(struct i2c_client *client)
619615
tps, DEBUG_FOPS);
620616

621617
/* optionally register GPIOs */
622-
if (board && board->base != 0) {
618+
if (board) {
623619
tps->outmask = board->outmask;
624620

625621
tps->chip.label = client->name;
@@ -632,7 +628,7 @@ static int tps65010_probe(struct i2c_client *client)
632628
/* NOTE: only partial support for inputs; nyet IRQs */
633629
tps->chip.get = tps65010_gpio_get;
634630

635-
tps->chip.base = board->base;
631+
tps->chip.base = -1;
636632
tps->chip.ngpio = 7;
637633
tps->chip.can_sleep = 1;
638634

@@ -641,7 +637,7 @@ static int tps65010_probe(struct i2c_client *client)
641637
dev_err(&client->dev, "can't add gpiochip, err %d\n",
642638
status);
643639
else if (board->setup) {
644-
status = board->setup(client, board->context);
640+
status = board->setup(client, &tps->chip);
645641
if (status < 0) {
646642
dev_dbg(&client->dev,
647643
"board %s %s err %d\n",

include/linux/mfd/tps65010.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#ifndef __LINUX_I2C_TPS65010_H
2929
#define __LINUX_I2C_TPS65010_H
3030

31+
struct gpio_chip;
32+
3133
/*
3234
* ----------------------------------------------------------------------------
3335
* Registers, all 8 bits
@@ -176,12 +178,10 @@ struct i2c_client;
176178

177179
/**
178180
* struct tps65010_board - packages GPIO and LED lines
179-
* @base: the GPIO number to assign to GPIO-1
180181
* @outmask: bit (N-1) is set to allow GPIO-N to be used as an
181182
* (open drain) output
182183
* @setup: optional callback issued once the GPIOs are valid
183184
* @teardown: optional callback issued before the GPIOs are invalidated
184-
* @context: optional parameter passed to setup() and teardown()
185185
*
186186
* Board data may be used to package the GPIO (and LED) lines for use
187187
* in by the generic GPIO and LED frameworks. The first four GPIOs
@@ -193,12 +193,9 @@ struct i2c_client;
193193
* devices in their initial states using these GPIOs.
194194
*/
195195
struct tps65010_board {
196-
int base;
197196
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);
202199
};
203200

204201
#endif /* __LINUX_I2C_TPS65010_H */

0 commit comments

Comments
 (0)