diff options
Diffstat (limited to 'drivers/i2c/chips')
-rw-r--r-- | drivers/i2c/chips/Kconfig | 1 | ||||
-rw-r--r-- | drivers/i2c/chips/isp1301_omap.c | 28 | ||||
-rw-r--r-- | drivers/i2c/chips/tps65010.c | 101 |
3 files changed, 115 insertions, 15 deletions
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index b21593f9358..2da2edfa68e 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -93,6 +93,7 @@ config ISP1301_OMAP config TPS65010 tristate "TPS6501x Power Management chips" + depends on HAVE_GPIO_LIB default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK help If you say yes here you get support for the TPS6501x series of diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c index 2a3160153f5..b1b45dddb17 100644 --- a/drivers/i2c/chips/isp1301_omap.c +++ b/drivers/i2c/chips/isp1301_omap.c @@ -658,7 +658,7 @@ pulldown: OTG_CTRL_REG |= OTG_PULLUP; } - check_state(isp, __FUNCTION__); + check_state(isp, __func__); dump_regs(isp, "otg->isp1301"); } @@ -782,7 +782,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp) if (otg_ctrl & OTG_DRIVER_SEL) { switch (isp->otg.state) { case OTG_STATE_A_IDLE: - b_idle(isp, __FUNCTION__); + b_idle(isp, __func__); break; default: break; @@ -826,7 +826,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp) isp->otg.host->otg_port); } - check_state(isp, __FUNCTION__); + check_state(isp, __func__); return ret; } @@ -837,7 +837,7 @@ static int otg_init(struct isp1301 *isp) if (!otg_dev) return -ENODEV; - dump_regs(isp, __FUNCTION__); + dump_regs(isp, __func__); /* some of these values are board-specific... */ OTG_SYSCON_2_REG |= OTG_EN /* for B-device: */ @@ -853,9 +853,9 @@ static int otg_init(struct isp1301 *isp) update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE)); update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS)); - check_state(isp, __FUNCTION__); + check_state(isp, __func__); pr_debug("otg: %s, %s %06x\n", - state_name(isp), __FUNCTION__, OTG_CTRL_REG); + state_name(isp), __func__, OTG_CTRL_REG); OTG_IRQ_EN_REG = DRIVER_SWITCH | OPRT_CHG | B_SRP_TMROUT | B_HNP_FAIL @@ -1041,11 +1041,11 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat) OTG1_DP_PULLDOWN); isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLUP); - dump_regs(isp, __FUNCTION__); + dump_regs(isp, __func__); #endif /* FALLTHROUGH */ case OTG_STATE_B_SRP_INIT: - b_idle(isp, __FUNCTION__); + b_idle(isp, __func__); OTG_CTRL_REG &= OTG_CTRL_REG & OTG_XCEIV_OUTPUTS; /* FALLTHROUGH */ case OTG_STATE_B_IDLE: @@ -1077,7 +1077,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat) */ update_otg1(isp, isp_stat); update_otg2(isp, isp_bstat); - check_state(isp, __FUNCTION__); + check_state(isp, __func__); #endif dump_regs(isp, "isp1301->otg"); @@ -1310,7 +1310,7 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host) */ isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_VBUS_DRV); - dump_regs(isp, __FUNCTION__); + dump_regs(isp, __func__); return 0; @@ -1365,7 +1365,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget) isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, INTR_VBUS_VLD); dev_info(&isp->client.dev, "B-Peripheral sessions ok\n"); - dump_regs(isp, __FUNCTION__); + dump_regs(isp, __func__); /* If this has a Mini-AB connector, this mode is highly * nonstandard ... but can be handy for testing, so long @@ -1416,7 +1416,7 @@ isp1301_start_srp(struct otg_transceiver *dev) pr_debug("otg: SRP, %s ... %06x\n", state_name(isp), OTG_CTRL_REG); #ifdef CONFIG_USB_OTG - check_state(isp, __FUNCTION__); + check_state(isp, __func__); #endif return 0; } @@ -1463,7 +1463,7 @@ isp1301_start_hnp(struct otg_transceiver *dev) } pr_debug("otg: HNP %s, %06x ...\n", state_name(isp), OTG_CTRL_REG); - check_state(isp, __FUNCTION__); + check_state(isp, __func__); return 0; #else /* srp-only */ @@ -1601,7 +1601,7 @@ fail2: update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS)); #endif - dump_regs(isp, __FUNCTION__); + dump_regs(isp, __func__); #ifdef VERBOSE mod_timer(&isp->timer, jiffies + TIMER_JIFFIES); diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c index 4154a910885..b67f69c2e7f 100644 --- a/drivers/i2c/chips/tps65010.c +++ b/drivers/i2c/chips/tps65010.c @@ -30,9 +30,13 @@ #include <linux/debugfs.h> #include <linux/seq_file.h> #include <linux/mutex.h> +#include <linux/platform_device.h> #include <linux/i2c/tps65010.h> +#include <asm/gpio.h> + + /*-------------------------------------------------------------------------*/ #define DRIVER_VERSION "2 May 2005" @@ -84,7 +88,9 @@ struct tps65010 { u8 chgstatus, regstatus, chgconf; 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) @@ -449,12 +455,72 @@ static irqreturn_t tps65010_irq(int irq, void *_tps) /*-------------------------------------------------------------------------*/ +/* 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 int __exit tps65010_remove(struct i2c_client *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) free_irq(client->irq, tps); cancel_delayed_work(&tps->work); @@ -469,6 +535,7 @@ static int tps65010_probe(struct i2c_client *client) { struct tps65010 *tps; int status; + struct tps65010_board *board = client->dev.platform_data; if (the_tps) { dev_dbg(&client->dev, "only one tps6501x chip allowed\n"); @@ -577,6 +644,38 @@ static int tps65010_probe(struct i2c_client *client) tps->file = debugfs_create_file(DRIVER_NAME, S_IRUGO, NULL, 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; fail1: kfree(tps); |