Commit 79966fd9 authored by David Brownell's avatar David Brownell Committed by Tony Lindgren

ARM: OMAP: I2C: tps65010 driver converts to gpiolib

Make the tps65010 driver use gpiolib to expose its GPIOs.

Note: This patch will get merged via omap tree instead of I2C
as it will cause some board updates. This has been discussed
at on the I2C list:

http://lists.lm-sensors.org/pipermail/i2c/2008-March/003031.htmlSigned-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Cc: i2c@lm-sensors.org
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent ac37a0b0
...@@ -93,6 +93,7 @@ config ISP1301_OMAP ...@@ -93,6 +93,7 @@ config ISP1301_OMAP
config TPS65010 config TPS65010
tristate "TPS6501x Power Management chips" tristate "TPS6501x Power Management chips"
depends on HAVE_GPIO_LIB
default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK
help help
If you say yes here you get support for the TPS6501x series of If you say yes here you get support for the TPS6501x series of
......
...@@ -30,9 +30,13 @@ ...@@ -30,9 +30,13 @@
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/i2c/tps65010.h> #include <linux/i2c/tps65010.h>
#include <asm/gpio.h>
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#define DRIVER_VERSION "2 May 2005" #define DRIVER_VERSION "2 May 2005"
...@@ -84,7 +88,9 @@ struct tps65010 { ...@@ -84,7 +88,9 @@ struct tps65010 {
u8 chgstatus, regstatus, chgconf; u8 chgstatus, regstatus, chgconf;
u8 nmask1, nmask2; u8 nmask1, nmask2;
/* not currently tracking GPIO state */ u8 outmask;
struct gpio_chip chip;
struct platform_device *leds;
}; };
#define POWER_POLL_DELAY msecs_to_jiffies(5000) #define POWER_POLL_DELAY msecs_to_jiffies(5000)
...@@ -447,6 +453,59 @@ static irqreturn_t tps65010_irq(int irq, void *_tps) ...@@ -447,6 +453,59 @@ static irqreturn_t tps65010_irq(int irq, void *_tps)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
/*-------------------------------------------------------------------------*/
/* offsets 0..3 == GPIO1..GPIO4
* offsets 4..5 == LED1/nPG, LED2 (we set one of the non-BLINK modes)
*/
static void
tps65010_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
if (offset < 4)
tps65010_set_gpio_out_value(offset + 1, value);
else
tps65010_set_led(offset - 3, value ? ON : OFF);
}
static int
tps65010_output(struct gpio_chip *chip, unsigned offset, int value)
{
/* GPIOs may be input-only */
if (offset < 4) {
struct tps65010 *tps;
tps = container_of(chip, struct tps65010, chip);
if (!(tps->outmask & (1 << offset)))
return -EINVAL;
tps65010_set_gpio_out_value(offset + 1, value);
} else
tps65010_set_led(offset - 3, value ? ON : OFF);
return 0;
}
static int tps65010_gpio_get(struct gpio_chip *chip, unsigned offset)
{
int value;
struct tps65010 *tps;
tps = container_of(chip, struct tps65010, chip);
if (offset < 4) {
value = i2c_smbus_read_byte_data(tps->client, TPS_DEFGPIO);
if (value < 0)
return 0;
if (value & (1 << (offset + 4))) /* output */
return !(value & (1 << offset));
else /* input */
return (value & (1 << offset));
}
/* REVISIT we *could* report LED1/nPG and LED2 state ... */
return 0;
}
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static struct tps65010 *the_tps; static struct tps65010 *the_tps;
...@@ -454,7 +513,14 @@ static struct tps65010 *the_tps; ...@@ -454,7 +513,14 @@ static struct tps65010 *the_tps;
static int __exit tps65010_remove(struct i2c_client *client) static int __exit tps65010_remove(struct i2c_client *client)
{ {
struct tps65010 *tps = i2c_get_clientdata(client); struct tps65010 *tps = i2c_get_clientdata(client);
struct tps65010_board *board = client->dev.platform_data;
if (board && board->teardown) {
int status = board->teardown(client, board->context);
if (status < 0)
dev_dbg(&client->dev, "board %s %s err %d\n",
"teardown", client->name, status);
}
if (client->irq > 0) if (client->irq > 0)
free_irq(client->irq, tps); free_irq(client->irq, tps);
cancel_delayed_work(&tps->work); cancel_delayed_work(&tps->work);
...@@ -469,6 +535,7 @@ static int tps65010_probe(struct i2c_client *client) ...@@ -469,6 +535,7 @@ static int tps65010_probe(struct i2c_client *client)
{ {
struct tps65010 *tps; struct tps65010 *tps;
int status; int status;
struct tps65010_board *board = client->dev.platform_data;
if (the_tps) { if (the_tps) {
dev_dbg(&client->dev, "only one tps6501x chip allowed\n"); dev_dbg(&client->dev, "only one tps6501x chip allowed\n");
...@@ -577,6 +644,38 @@ static int tps65010_probe(struct i2c_client *client) ...@@ -577,6 +644,38 @@ static int tps65010_probe(struct i2c_client *client)
tps->file = debugfs_create_file(DRIVER_NAME, S_IRUGO, NULL, tps->file = debugfs_create_file(DRIVER_NAME, S_IRUGO, NULL,
tps, DEBUG_FOPS); tps, DEBUG_FOPS);
/* optionally register GPIOs */
if (board && board->base > 0) {
tps->outmask = board->outmask;
tps->chip.label = client->name;
tps->chip.set = tps65010_gpio_set;
tps->chip.direction_output = tps65010_output;
/* NOTE: only partial support for inputs; nyet IRQs */
tps->chip.get = tps65010_gpio_get;
tps->chip.base = board->base;
tps->chip.ngpio = 6;
tps->chip.can_sleep = 1;
status = gpiochip_add(&tps->chip);
if (status < 0)
dev_err(&client->dev, "can't add gpiochip, err %d\n",
status);
else if (board->setup) {
status = board->setup(client, board->context);
if (status < 0) {
dev_dbg(&client->dev,
"board %s %s err %d\n",
"setup", client->name, status);
status = 0;
}
}
}
return 0; return 0;
fail1: fail1:
kfree(tps); kfree(tps);
......
...@@ -152,5 +152,35 @@ extern int tps65010_config_vregs1(unsigned value); ...@@ -152,5 +152,35 @@ extern int tps65010_config_vregs1(unsigned value);
*/ */
extern int tps65013_set_low_pwr(unsigned mode); extern int tps65013_set_low_pwr(unsigned mode);
struct i2c_client;
/**
* struct tps65010_board - packages GPIO and LED lines
* @base: the GPIO number to assign to GPIO-1
* @outmask: bit (N-1) is set to allow GPIO-N to be used as an
* (open drain) output
* @setup: optional callback issued once the GPIOs are valid
* @teardown: optional callback issued before the GPIOs are invalidated
* @context: optional parameter passed to setup() and teardown()
*
* Board data may be used to package the GPIO (and LED) lines for use
* in by the generic GPIO and LED frameworks. The first four GPIOs
* starting at gpio_base are GPIO1..GPIO4. The next two are LED1/nPG
* and LED2 (with hardware blinking capability, not currently exposed).
*
* The @setup callback may be used with the kind of board-specific glue
* which hands the (now-valid) GPIOs to other drivers, or which puts
* devices in their initial states using these GPIOs.
*/
struct tps65010_board {
int base;
unsigned outmask;
int (*setup)(struct i2c_client *client, void *context);
int (*teardown)(struct i2c_client *client, void *context);
void *context;
};
#endif /* __LINUX_I2C_TPS65010_H */ #endif /* __LINUX_I2C_TPS65010_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment