From aa6f5ffbdba45aa8e19e5048648fc6c7b25376d3 Mon Sep 17 00:00:00 2001 From: merge Date: Thu, 22 Jan 2009 13:55:32 +0000 Subject: MERGE-via-pending-tracking-hist-MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141 pending-tracking-hist top was MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141 / fdf777a63bcb59e0dfd78bfe2c6242e01f6d4eb9 ... parent commitmessage: From: merge MERGE-via-stable-tracking-hist-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040 stable-tracking-hist top was MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040 / 90463bfd2d5a3c8b52f6e6d71024a00e052b0ced ... parent commitmessage: From: merge MERGE-via-mokopatches-tracking-hist-fix-stray-endmenu-patch mokopatches-tracking-hist top was fix-stray-endmenu-patch / 3630e0be570de8057e7f8d2fe501ed353cdf34e6 ... parent commitmessage: From: Andy Green fix-stray-endmenu.patch Signed-off-by: Andy Green --- drivers/i2c/busses/i2c-ali1563.c | 4 +- drivers/i2c/busses/i2c-amd756-s4882.c | 4 +- drivers/i2c/busses/i2c-amd756.c | 5 +- drivers/i2c/busses/i2c-at91.c | 2 +- drivers/i2c/busses/i2c-bfin-twi.c | 2 +- drivers/i2c/busses/i2c-cpm.c | 1 + drivers/i2c/busses/i2c-highlander.c | 4 +- drivers/i2c/busses/i2c-i801.c | 50 +- drivers/i2c/busses/i2c-omap.c | 420 +++++++-- drivers/i2c/busses/i2c-parport.c | 4 +- drivers/i2c/busses/i2c-pmcmsp.c | 2 +- drivers/i2c/busses/i2c-pxa.c | 6 +- drivers/i2c/busses/i2c-s3c2410.c | 2 +- drivers/i2c/busses/i2c-sh7760.c | 2 +- drivers/i2c/busses/i2c-sh_mobile.c | 78 +- drivers/i2c/busses/i2c-sis5595.c | 4 +- drivers/i2c/busses/i2c-sis630.c | 4 +- drivers/i2c/chips/Kconfig | 56 -- drivers/i2c/chips/Makefile | 5 - drivers/i2c/chips/isp1301_omap.c | 1654 --------------------------------- drivers/i2c/chips/mcu_mpc8349emitx.c | 209 ----- drivers/i2c/chips/menelaus.c | 1285 ------------------------- drivers/i2c/chips/pcf50633.h | 349 +++++++ drivers/i2c/chips/tps65010.c | 1072 --------------------- drivers/i2c/i2c-core.c | 10 +- 25 files changed, 794 insertions(+), 4440 deletions(-) delete mode 100644 drivers/i2c/chips/isp1301_omap.c delete mode 100644 drivers/i2c/chips/mcu_mpc8349emitx.c delete mode 100644 drivers/i2c/chips/menelaus.c create mode 100644 drivers/i2c/chips/pcf50633.h delete mode 100644 drivers/i2c/chips/tps65010.c (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index fc3e5b02642..dd9e796fad6 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -399,8 +399,8 @@ static int __devinit ali1563_probe(struct pci_dev * dev, if ((error = ali1563_setup(dev))) goto exit; ali1563_adapter.dev.parent = &dev->dev; - sprintf(ali1563_adapter.name,"SMBus ALi 1563 Adapter @ %04x", - ali1563_smba); + snprintf(ali1563_adapter.name, sizeof(ali1563_adapter.name), + "SMBus ALi 1563 Adapter @ %04x", ali1563_smba); if ((error = i2c_add_adapter(&ali1563_adapter))) goto exit_shutdown; return 0; diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c index 8ba2bcf727d..378fcb5d578 100644 --- a/drivers/i2c/busses/i2c-amd756-s4882.c +++ b/drivers/i2c/busses/i2c-amd756-s4882.c @@ -197,8 +197,8 @@ static int __init amd756_s4882_init(void) for (i = 1; i < 5; i++) { s4882_algo[i] = *(amd756_smbus.algo); s4882_adapter[i] = amd756_smbus; - sprintf(s4882_adapter[i].name, - "SMBus 8111 adapter (CPU%d)", i-1); + snprintf(s4882_adapter[i].name, sizeof(s4882_adapter[i].name), + "SMBus 8111 adapter (CPU%d)", i-1); s4882_adapter[i].algo = s4882_algo+i; s4882_adapter[i].dev.parent = amd756_smbus.dev.parent; } diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 424dad6f18d..36bee5b9c95 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -380,8 +380,9 @@ static int __devinit amd756_probe(struct pci_dev *pdev, /* set up the sysfs linkage to our parent device */ amd756_smbus.dev.parent = &pdev->dev; - sprintf(amd756_smbus.name, "SMBus %s adapter at %04x", - chipname[id->driver_data], amd756_ioport); + snprintf(amd756_smbus.name, sizeof(amd756_smbus.name), + "SMBus %s adapter at %04x", chipname[id->driver_data], + amd756_ioport); error = i2c_add_adapter(&amd756_smbus); if (error) { diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 9efb0213725..67d9dc5b351 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -222,7 +222,7 @@ static int __devinit at91_i2c_probe(struct platform_device *pdev) rc = -ENOMEM; goto fail2; } - sprintf(adapter->name, "AT91"); + snprintf(adapter->name, sizeof(adapter->name), "AT91"); adapter->algo = &at91_algorithm; adapter->class = I2C_CLASS_HWMON; adapter->dev.parent = &pdev->dev; diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 3c855ff2992..3fd2c417c1e 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -656,7 +656,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name)); p_adap->algo = &bfin_twi_algorithm; p_adap->algo_data = iface; - p_adap->class = I2C_CLASS_ALL; + p_adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; p_adap->dev.parent = &pdev->dev; rc = peripheral_request_list(pin_req[pdev->id], "i2c-bfin-twi"); diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index 228f7572306..3fcf78e906d 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -365,6 +365,7 @@ static int cpm_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) pmsg = &msgs[tptr]; if (pmsg->flags & I2C_M_RD) ret = wait_event_interruptible_timeout(cpm->i2c_wait, + (in_be16(&tbdf[tptr].cbd_sc) & BD_SC_NAK) || !(in_be16(&rbdf[rptr].cbd_sc) & BD_SC_EMPTY), 1 * HZ); else diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c index f4d22ae9d29..e5a8dae4a28 100644 --- a/drivers/i2c/busses/i2c-highlander.c +++ b/drivers/i2c/busses/i2c-highlander.c @@ -92,7 +92,7 @@ static void highlander_i2c_setup(struct highlander_i2c_dev *dev) static void smbus_write_data(u8 *src, u16 *dst, int len) { for (; len > 1; len -= 2) { - *dst++ = be16_to_cpup((u16 *)src); + *dst++ = be16_to_cpup((__be16 *)src); src += 2; } @@ -103,7 +103,7 @@ static void smbus_write_data(u8 *src, u16 *dst, int len) static void smbus_read_data(u16 *src, u8 *dst, int len) { for (; len > 1; len -= 2) { - *(u16 *)dst = cpu_to_be16p(src++); + *(__be16 *)dst = cpu_to_be16p(src++); dst += 2; } diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 5123eb69a97..526625eaa84 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -64,7 +64,7 @@ #include #include #include -#include +#include /* I801 SMBus address offsets */ #define SMBHSTSTS (0 + i801_smba) @@ -583,6 +583,40 @@ static struct pci_device_id i801_ids[] = { MODULE_DEVICE_TABLE (pci, i801_ids); +#if defined CONFIG_INPUT_APANEL || defined CONFIG_INPUT_APANEL_MODULE +static unsigned char apanel_addr; + +/* Scan the system ROM for the signature "FJKEYINF" */ +static __init const void __iomem *bios_signature(const void __iomem *bios) +{ + ssize_t offset; + const unsigned char signature[] = "FJKEYINF"; + + for (offset = 0; offset < 0x10000; offset += 0x10) { + if (check_signature(bios + offset, signature, + sizeof(signature)-1)) + return bios + offset; + } + return NULL; +} + +static void __init input_apanel_init(void) +{ + void __iomem *bios; + const void __iomem *p; + + bios = ioremap(0xF0000, 0x10000); /* Can't fail */ + p = bios_signature(bios); + if (p) { + /* just use the first address */ + apanel_addr = readb(p + 8 + 3) >> 1; + } + iounmap(bios); +} +#else +static void __init input_apanel_init(void) {} +#endif + static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id) { unsigned char temp; @@ -667,6 +701,19 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id dev_err(&dev->dev, "Failed to add SMBus adapter\n"); goto exit_release; } + + /* Register optional slaves */ +#if defined CONFIG_INPUT_APANEL || defined CONFIG_INPUT_APANEL_MODULE + if (apanel_addr) { + struct i2c_board_info info; + + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = apanel_addr; + strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE); + i2c_new_device(&i801_adapter, &info); + } +#endif + return 0; exit_release: @@ -717,6 +764,7 @@ static struct pci_driver i801_driver = { static int __init i2c_i801_init(void) { + input_apanel_init(); return pci_register_driver(&i801_driver); } diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 608038d64f8..be8ee2cac8b 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -2,13 +2,16 @@ * TI OMAP I2C master mode driver * * Copyright (C) 2003 MontaVista Software, Inc. - * Copyright (C) 2004 Texas Instruments. - * - * Updated to work with multiple I2C interfaces on 24xx by - * Tony Lindgren and Imre Deak * Copyright (C) 2005 Nokia Corporation + * Copyright (C) 2004 - 2007 Texas Instruments. * - * Cleaned up by Juha Yrjölä + * Originally written by MontaVista Software, Inc. + * Additional contributions by: + * Tony Lindgren + * Imre Deak + * Juha Yrjölä + * Syed Khasim + * Nishant Menon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,8 +36,14 @@ #include #include #include +#include + +/* I2C controller revisions */ +#define OMAP_I2C_REV_2 0x20 -#include +/* I2C controller revisions present on specific hardware */ +#define OMAP_I2C_REV_ON_2430 0x36 +#define OMAP_I2C_REV_ON_3430 0x3C /* timeout waiting for the controller to respond */ #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) @@ -43,6 +52,8 @@ #define OMAP_I2C_IE_REG 0x04 #define OMAP_I2C_STAT_REG 0x08 #define OMAP_I2C_IV_REG 0x0c +/* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */ +#define OMAP_I2C_WE_REG 0x0c #define OMAP_I2C_SYSS_REG 0x10 #define OMAP_I2C_BUF_REG 0x14 #define OMAP_I2C_CNT_REG 0x18 @@ -55,8 +66,11 @@ #define OMAP_I2C_SCLL_REG 0x34 #define OMAP_I2C_SCLH_REG 0x38 #define OMAP_I2C_SYSTEST_REG 0x3c +#define OMAP_I2C_BUFSTAT_REG 0x40 /* I2C Interrupt Enable Register (OMAP_I2C_IE): */ +#define OMAP_I2C_IE_XDR (1 << 14) /* TX Buffer drain int enable */ +#define OMAP_I2C_IE_RDR (1 << 13) /* RX Buffer drain int enable */ #define OMAP_I2C_IE_XRDY (1 << 4) /* TX data ready int enable */ #define OMAP_I2C_IE_RRDY (1 << 3) /* RX data ready int enable */ #define OMAP_I2C_IE_ARDY (1 << 2) /* Access ready int enable */ @@ -64,7 +78,8 @@ #define OMAP_I2C_IE_AL (1 << 0) /* Arbitration lost int ena */ /* I2C Status Register (OMAP_I2C_STAT): */ -#define OMAP_I2C_STAT_SBD (1 << 15) /* Single byte data */ +#define OMAP_I2C_STAT_XDR (1 << 14) /* TX Buffer draining */ +#define OMAP_I2C_STAT_RDR (1 << 13) /* RX Buffer draining */ #define OMAP_I2C_STAT_BB (1 << 12) /* Bus busy */ #define OMAP_I2C_STAT_ROVR (1 << 11) /* Receive overrun */ #define OMAP_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */ @@ -76,13 +91,34 @@ #define OMAP_I2C_STAT_NACK (1 << 1) /* No ack interrupt enable */ #define OMAP_I2C_STAT_AL (1 << 0) /* Arbitration lost int ena */ +/* I2C WE wakeup enable register */ +#define OMAP_I2C_WE_XDR_WE (1 << 14) /* TX drain wakup */ +#define OMAP_I2C_WE_RDR_WE (1 << 13) /* RX drain wakeup */ +#define OMAP_I2C_WE_AAS_WE (1 << 9) /* Address as slave wakeup*/ +#define OMAP_I2C_WE_BF_WE (1 << 8) /* Bus free wakeup */ +#define OMAP_I2C_WE_STC_WE (1 << 6) /* Start condition wakeup */ +#define OMAP_I2C_WE_GC_WE (1 << 5) /* General call wakeup */ +#define OMAP_I2C_WE_DRDY_WE (1 << 3) /* TX/RX data ready wakeup */ +#define OMAP_I2C_WE_ARDY_WE (1 << 2) /* Reg access ready wakeup */ +#define OMAP_I2C_WE_NACK_WE (1 << 1) /* No acknowledgment wakeup */ +#define OMAP_I2C_WE_AL_WE (1 << 0) /* Arbitration lost wakeup */ + +#define OMAP_I2C_WE_ALL (OMAP_I2C_WE_XDR_WE | OMAP_I2C_WE_RDR_WE | \ + OMAP_I2C_WE_AAS_WE | OMAP_I2C_WE_BF_WE | \ + OMAP_I2C_WE_STC_WE | OMAP_I2C_WE_GC_WE | \ + OMAP_I2C_WE_DRDY_WE | OMAP_I2C_WE_ARDY_WE | \ + OMAP_I2C_WE_NACK_WE | OMAP_I2C_WE_AL_WE) + /* I2C Buffer Configuration Register (OMAP_I2C_BUF): */ #define OMAP_I2C_BUF_RDMA_EN (1 << 15) /* RX DMA channel enable */ +#define OMAP_I2C_BUF_RXFIF_CLR (1 << 14) /* RX FIFO Clear */ #define OMAP_I2C_BUF_XDMA_EN (1 << 7) /* TX DMA channel enable */ +#define OMAP_I2C_BUF_TXFIF_CLR (1 << 6) /* TX FIFO Clear */ /* I2C Configuration Register (OMAP_I2C_CON): */ #define OMAP_I2C_CON_EN (1 << 15) /* I2C module enable */ #define OMAP_I2C_CON_BE (1 << 14) /* Big endian mode */ +#define OMAP_I2C_CON_OPMODE_HS (1 << 12) /* High Speed support */ #define OMAP_I2C_CON_STB (1 << 11) /* Start byte mode (master) */ #define OMAP_I2C_CON_MST (1 << 10) /* Master/slave mode */ #define OMAP_I2C_CON_TRX (1 << 9) /* TX/RX mode (master only) */ @@ -91,6 +127,10 @@ #define OMAP_I2C_CON_STP (1 << 1) /* Stop cond (master only) */ #define OMAP_I2C_CON_STT (1 << 0) /* Start condition (master) */ +/* I2C SCL time value when Master */ +#define OMAP_I2C_SCLL_HSSCLL 8 +#define OMAP_I2C_SCLH_HSSCLH 8 + /* I2C System Test Register (OMAP_I2C_SYSTEST): */ #ifdef DEBUG #define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */ @@ -103,17 +143,19 @@ #define OMAP_I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive out */ #endif -/* I2C System Status register (OMAP_I2C_SYSS): */ -#define OMAP_I2C_SYSS_RDONE (1 << 0) /* Reset Done */ +/* OCP_SYSSTATUS bit definitions */ +#define SYSS_RESETDONE_MASK (1 << 0) + +/* OCP_SYSCONFIG bit definitions */ +#define SYSC_CLOCKACTIVITY_MASK (0x3 << 8) +#define SYSC_SIDLEMODE_MASK (0x3 << 3) +#define SYSC_ENAWAKEUP_MASK (1 << 2) +#define SYSC_SOFTRESET_MASK (1 << 1) +#define SYSC_AUTOIDLE_MASK (1 << 0) -/* I2C System Configuration Register (OMAP_I2C_SYSC): */ -#define OMAP_I2C_SYSC_SRST (1 << 1) /* Soft Reset */ +#define SYSC_IDLEMODE_SMART 0x2 +#define SYSC_CLOCKACTIVITY_FCLK 0x2 -/* REVISIT: Use platform_data instead of module parameters */ -/* Fast Mode = 400 kHz, Standard = 100 kHz */ -static int clock = 100; /* Default: 100 kHz */ -module_param(clock, int, 0); -MODULE_PARM_DESC(clock, "Set I2C clock in kHz: 400=fast mode (default == 100)"); struct omap_i2c_dev { struct device *dev; @@ -123,11 +165,17 @@ struct omap_i2c_dev { struct clk *fclk; /* Functional clock */ struct completion cmd_complete; struct resource *ioarea; + u32 speed; /* Speed of bus in Khz */ u16 cmd_err; u8 *buf; size_t buf_len; struct i2c_adapter adapter; - unsigned rev1:1; + u8 fifo_size; /* use as flag and value + * fifo_size==0 implies no fifo + * if set, should be trsh+1 + */ + u8 rev; + unsigned b_hw:1; /* bad h/w fixes */ unsigned idle:1; u16 iestate; /* Saved interrupt register */ }; @@ -143,9 +191,9 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg) return __raw_readw(i2c_dev->base + reg); } -static int omap_i2c_get_clocks(struct omap_i2c_dev *dev) +static int __init omap_i2c_get_clocks(struct omap_i2c_dev *dev) { - if (cpu_is_omap16xx() || cpu_is_omap24xx()) { + if (cpu_is_omap16xx() || cpu_class_is_omap2()) { dev->iclk = clk_get(dev->dev, "i2c_ick"); if (IS_ERR(dev->iclk)) { dev->iclk = NULL; @@ -178,25 +226,33 @@ static void omap_i2c_put_clocks(struct omap_i2c_dev *dev) static void omap_i2c_unidle(struct omap_i2c_dev *dev) { + WARN_ON(!dev->idle); + if (dev->iclk != NULL) clk_enable(dev->iclk); clk_enable(dev->fclk); + dev->idle = 0; if (dev->iestate) omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate); - dev->idle = 0; } static void omap_i2c_idle(struct omap_i2c_dev *dev) { u16 iv; - dev->idle = 1; + WARN_ON(dev->idle); + dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0); - if (dev->rev1) - iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */ - else + if (dev->rev < OMAP_I2C_REV_2) { + iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */ + } else { omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, dev->iestate); + + /* Flush posted write before the dev->idle store occurs */ + omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + } + dev->idle = 1; clk_disable(dev->fclk); if (dev->iclk != NULL) clk_disable(dev->iclk); @@ -204,18 +260,20 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev) static int omap_i2c_init(struct omap_i2c_dev *dev) { - u16 psc = 0; + u16 psc = 0, scll = 0, sclh = 0; + u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0; unsigned long fclk_rate = 12000000; unsigned long timeout; + unsigned long internal_clk = 0; - if (!dev->rev1) { - omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, OMAP_I2C_SYSC_SRST); + if (dev->rev >= OMAP_I2C_REV_2) { + omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, SYSC_SOFTRESET_MASK); /* For some reason we need to set the EN bit before the * reset done bit gets set. */ timeout = jiffies + OMAP_I2C_TIMEOUT; omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); while (!(omap_i2c_read_reg(dev, OMAP_I2C_SYSS_REG) & - OMAP_I2C_SYSS_RDONE)) { + SYSS_RESETDONE_MASK)) { if (time_after(jiffies, timeout)) { dev_warn(dev->dev, "timeout waiting " "for controller reset\n"); @@ -223,6 +281,33 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) } msleep(1); } + + /* SYSC register is cleared by the reset; rewrite it */ + if (dev->rev == OMAP_I2C_REV_ON_2430) { + + omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, + SYSC_AUTOIDLE_MASK); + + } else if (dev->rev >= OMAP_I2C_REV_ON_3430) { + u32 v; + + v = SYSC_AUTOIDLE_MASK; + v |= SYSC_ENAWAKEUP_MASK; + v |= (SYSC_IDLEMODE_SMART << + __ffs(SYSC_SIDLEMODE_MASK)); + v |= (SYSC_CLOCKACTIVITY_FCLK << + __ffs(SYSC_CLOCKACTIVITY_MASK)); + + omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, v); + /* + * Enabling all wakup sources to stop I2C freezing on + * WFI instruction. + * REVISIT: Some wkup sources might not be needed. + */ + omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, + OMAP_I2C_WE_ALL); + + } } omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); @@ -249,27 +334,65 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) psc = fclk_rate / 12000000; } + if (cpu_is_omap2430() || cpu_is_omap34xx()) { + + /* HSI2C controller internal clk rate should be 19.2 Mhz */ + internal_clk = 19200; + fclk_rate = clk_get_rate(dev->fclk) / 1000; + + /* Compute prescaler divisor */ + psc = fclk_rate / internal_clk; + psc = psc - 1; + + /* If configured for High Speed */ + if (dev->speed > 400) { + /* For first phase of HS mode */ + fsscll = internal_clk / (400 * 2) - 6; + fssclh = internal_clk / (400 * 2) - 6; + + /* For second phase of HS mode */ + hsscll = fclk_rate / (dev->speed * 2) - 6; + hssclh = fclk_rate / (dev->speed * 2) - 6; + } else { + /* To handle F/S modes */ + fsscll = internal_clk / (dev->speed * 2) - 6; + fssclh = internal_clk / (dev->speed * 2) - 6; + } + scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll; + sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh; + } else { + /* Program desired operating rate */ + fclk_rate /= (psc + 1) * 1000; + if (psc > 2) + psc = 2; + scll = fclk_rate / (dev->speed * 2) - 7 + psc; + sclh = fclk_rate / (dev->speed * 2) - 7 + psc; + } + /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */ omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, psc); - /* Program desired operating rate */ - fclk_rate /= (psc + 1) * 1000; - if (psc > 2) - psc = 2; + /* SCL low and high time values */ + omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll); + omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh); - omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, - fclk_rate / (clock * 2) - 7 + psc); - omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, - fclk_rate / (clock * 2) - 7 + psc); + if (dev->fifo_size) + /* Note: setup required fifo size - 1 */ + omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, + (dev->fifo_size - 1) << 8 | /* RTRSH */ + OMAP_I2C_BUF_RXFIF_CLR | + (dev->fifo_size - 1) | /* XTRSH */ + OMAP_I2C_BUF_TXFIF_CLR); /* Take the I2C module out of reset: */ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); /* Enable interrupts */ omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, - (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY | - OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK | - OMAP_I2C_IE_AL)); + (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY | + OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK | + OMAP_I2C_IE_AL) | ((dev->fifo_size) ? + (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0)); return 0; } @@ -316,20 +439,59 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len); + /* Clear the FIFO Buffers */ + w = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG); + w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR; + omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w); + init_completion(&dev->cmd_complete); dev->cmd_err = 0; w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; + + /* High speed configuration */ + if (dev->speed > 400) + w |= OMAP_I2C_CON_OPMODE_HS; + if (msg->flags & I2C_M_TEN) w |= OMAP_I2C_CON_XA; if (!(msg->flags & I2C_M_RD)) w |= OMAP_I2C_CON_TRX; - if (stop) + + if (!dev->b_hw && stop) w |= OMAP_I2C_CON_STP; + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w); - r = wait_for_completion_interruptible_timeout(&dev->cmd_complete, - OMAP_I2C_TIMEOUT); + /* + * Don't write stt and stp together on some hardware. + */ + if (dev->b_hw && stop) { + unsigned long delay = jiffies + OMAP_I2C_TIMEOUT; + u16 con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG); + while (con & OMAP_I2C_CON_STT) { + con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG); + + /* Let the user know if i2c is in a bad state */ + if (time_after(jiffies, delay)) { + dev_err(dev->dev, "controller timed out " + "waiting for start condition to finish\n"); + return -ETIMEDOUT; + } + cpu_relax(); + } + + w |= OMAP_I2C_CON_STP; + w &= ~OMAP_I2C_CON_STT; + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w); + } + + /* + * REVISIT: We should abort the transfer on signals, but the bus goes + * into arbitration and we're currently unable to recover from it. + */ + r = wait_for_completion_timeout(&dev->cmd_complete, + OMAP_I2C_TIMEOUT); dev->buf_len = 0; if (r < 0) return r; @@ -376,7 +538,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) omap_i2c_unidle(dev); - if ((r = omap_i2c_wait_for_bb(dev)) < 0) + r = omap_i2c_wait_for_bb(dev); + if (r < 0) goto out; for (i = 0; i < num; i++) { @@ -411,6 +574,9 @@ omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat) omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat); } +/* rev1 devices are apparently only on some 15xx */ +#ifdef CONFIG_ARCH_OMAP15XX + static irqreturn_t omap_i2c_rev1_isr(int this_irq, void *dev_id) { @@ -465,6 +631,9 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id) return IRQ_HANDLED; } +#else +#define omap_i2c_rev1_isr NULL +#endif static irqreturn_t omap_i2c_isr(int this_irq, void *dev_id) @@ -472,7 +641,7 @@ omap_i2c_isr(int this_irq, void *dev_id) struct omap_i2c_dev *dev = dev_id; u16 bits; u16 stat, w; - int count = 0; + int err, count = 0; if (dev->idle) return IRQ_NONE; @@ -487,39 +656,96 @@ omap_i2c_isr(int this_irq, void *dev_id) omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat); - if (stat & OMAP_I2C_STAT_ARDY) { - omap_i2c_complete_cmd(dev, 0); - continue; + err = 0; + if (stat & OMAP_I2C_STAT_NACK) { + err |= OMAP_I2C_STAT_NACK; + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, + OMAP_I2C_CON_STP); } - if (stat & OMAP_I2C_STAT_RRDY) { - w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); - if (dev->buf_len) { - *dev->buf++ = w; - dev->buf_len--; + if (stat & OMAP_I2C_STAT_AL) { + dev_err(dev->dev, "Arbitration lost\n"); + err |= OMAP_I2C_STAT_AL; + } + if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK | + OMAP_I2C_STAT_AL)) + omap_i2c_complete_cmd(dev, err); + if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) { + u8 num_bytes = 1; + if (dev->fifo_size) { + if (stat & OMAP_I2C_STAT_RRDY) + num_bytes = dev->fifo_size; + else + num_bytes = omap_i2c_read_reg(dev, + OMAP_I2C_BUFSTAT_REG); + } + while (num_bytes) { + num_bytes--; + w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); if (dev->buf_len) { - *dev->buf++ = w >> 8; + *dev->buf++ = w; dev->buf_len--; + /* Data reg from 2430 is 8 bit wide */ + if (!cpu_is_omap2430() && + !cpu_is_omap34xx()) { + if (dev->buf_len) { + *dev->buf++ = w >> 8; + dev->buf_len--; + } + } + } else { + if (stat & OMAP_I2C_STAT_RRDY) + dev_err(dev->dev, + "RRDY IRQ while no data" + " requested\n"); + if (stat & OMAP_I2C_STAT_RDR) + dev_err(dev->dev, + "RDR IRQ while no data" + " requested\n"); + break; } - } else - dev_err(dev->dev, "RRDY IRQ while no data " - "requested\n"); - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY); + } + omap_i2c_ack_stat(dev, + stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)); continue; } - if (stat & OMAP_I2C_STAT_XRDY) { - w = 0; - if (dev->buf_len) { - w = *dev->buf++; - dev->buf_len--; + if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) { + u8 num_bytes = 1; + if (dev->fifo_size) { + if (stat & OMAP_I2C_STAT_XRDY) + num_bytes = dev->fifo_size; + else + num_bytes = omap_i2c_read_reg(dev, + OMAP_I2C_BUFSTAT_REG); + } + while (num_bytes) { + num_bytes--; + w = 0; if (dev->buf_len) { - w |= *dev->buf++ << 8; + w = *dev->buf++; dev->buf_len--; + /* Data reg from 2430 is 8 bit wide */ + if (!cpu_is_omap2430() && + !cpu_is_omap34xx()) { + if (dev->buf_len) { + w |= *dev->buf++ << 8; + dev->buf_len--; + } + } + } else { + if (stat & OMAP_I2C_STAT_XRDY) + dev_err(dev->dev, + "XRDY IRQ while no " + "data to send\n"); + if (stat & OMAP_I2C_STAT_XDR) + dev_err(dev->dev, + "XDR IRQ while no " + "data to send\n"); + break; } - } else - dev_err(dev->dev, "XRDY IRQ while no " - "data to send\n"); - omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY); + omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); + } + omap_i2c_ack_stat(dev, + stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); continue; } if (stat & OMAP_I2C_STAT_ROVR) { @@ -527,18 +753,9 @@ omap_i2c_isr(int this_irq, void *dev_id) dev->cmd_err |= OMAP_I2C_STAT_ROVR; } if (stat & OMAP_I2C_STAT_XUDF) { - dev_err(dev->dev, "Transmit overflow\n"); + dev_err(dev->dev, "Transmit underflow\n"); dev->cmd_err |= OMAP_I2C_STAT_XUDF; } - if (stat & OMAP_I2C_STAT_NACK) { - omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK); - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, - OMAP_I2C_CON_STP); - } - if (stat & OMAP_I2C_STAT_AL) { - dev_err(dev->dev, "Arbitration lost\n"); - omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL); - } } return count ? IRQ_HANDLED : IRQ_NONE; @@ -549,13 +766,15 @@ static const struct i2c_algorithm omap_i2c_algo = { .functionality = omap_i2c_func, }; -static int +static int __init omap_i2c_probe(struct platform_device *pdev) { struct omap_i2c_dev *dev; struct i2c_adapter *adap; struct resource *mem, *irq, *ioarea; + irq_handler_t isr; int r; + u32 speed = 0; /* NOTE: driver uses the static register mapping */ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -576,17 +795,19 @@ omap_i2c_probe(struct platform_device *pdev) return -EBUSY; } - if (clock > 200) - clock = 400; /* Fast mode */ - else - clock = 100; /* Standard mode */ - dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL); if (!dev) { r = -ENOMEM; goto err_release_region; } + if (pdev->dev.platform_data != NULL) + speed = *(u32 *)pdev->dev.platform_data; + else + speed = 100; /* Defualt speed */ + + dev->speed = speed; + dev->idle = 1; dev->dev = &pdev->dev; dev->irq = irq->start; dev->base = ioremap(mem->start, mem->end - mem->start + 1); @@ -602,22 +823,39 @@ omap_i2c_probe(struct platform_device *pdev) omap_i2c_unidle(dev); - if (cpu_is_omap15xx()) - dev->rev1 = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) < 0x20; + dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff; + + if (cpu_is_omap2430() || cpu_is_omap34xx()) { + u16 s; + + /* Set up the fifo size - Get total size */ + s = (omap_i2c_read_reg(dev, OMAP_I2C_BUFSTAT_REG) >> 14) & 0x3; + dev->fifo_size = 0x8 << s; + + /* + * Set up notification threshold as half the total available + * size. This is to ensure that we can handle the status on int + * call back latencies. + */ + dev->fifo_size = (dev->fifo_size / 2); + dev->b_hw = 1; /* Enable hardware fixes */ + } /* reset ASAP, clearing any IRQs */ omap_i2c_init(dev); - r = request_irq(dev->irq, dev->rev1 ? omap_i2c_rev1_isr : omap_i2c_isr, - 0, pdev->name, dev); + isr = (dev->rev < OMAP_I2C_REV_2) ? omap_i2c_rev1_isr : omap_i2c_isr; + r = request_irq(dev->irq, isr, 0, pdev->name, dev); if (r) { dev_err(dev->dev, "failure requesting irq %i\n", dev->irq); goto err_unuse_clocks; } - r = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff; + dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n", - pdev->id, r >> 4, r & 0xf, clock); + pdev->id, dev->rev >> 4, dev->rev & 0xf, dev->speed); + + omap_i2c_idle(dev); adap = &dev->adapter; i2c_set_adapdata(adap, dev); @@ -635,8 +873,6 @@ omap_i2c_probe(struct platform_device *pdev) goto err_free_irq; } - omap_i2c_idle(dev); - return 0; err_free_irq: diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 59ba2086d2f..a257cd5cd13 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -189,8 +189,6 @@ static void i2c_parport_attach (struct parport *port) if (adapter_parm[type].init.val) line_set(port, 1, &adapter_parm[type].init); - parport_release(adapter->pdev); - if (i2c_bit_add_bus(&adapter->adapter) < 0) { printk(KERN_ERR "i2c-parport: Unable to register with I2C\n"); goto ERROR1; @@ -202,6 +200,7 @@ static void i2c_parport_attach (struct parport *port) return; ERROR1: + parport_release(adapter->pdev); parport_unregister_device(adapter->pdev); ERROR0: kfree(adapter); @@ -221,6 +220,7 @@ static void i2c_parport_detach (struct parport *port) if (adapter_parm[type].init.val) line_set(port, 0, &adapter_parm[type].init); + parport_release(adapter->pdev); parport_unregister_device(adapter->pdev); if (prev) prev->next = adapter->next; diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c index dcf2045b522..0bdb2d7f057 100644 --- a/drivers/i2c/busses/i2c-pmcmsp.c +++ b/drivers/i2c/busses/i2c-pmcmsp.c @@ -486,7 +486,7 @@ static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd( if (cmd->type == MSP_TWI_CMD_WRITE || cmd->type == MSP_TWI_CMD_WRITE_READ) { - __be64 tmp = cpu_to_be64p((u64 *)cmd->write_data); + u64 tmp = be64_to_cpup((__be64 *)cmd->write_data); tmp >>= (MSP_MAX_BYTES_PER_RW - cmd->write_len) * 8; dev_dbg(&pmcmsptwi_adapter.dev, "Writing 0x%016llx\n", tmp); pmcmsptwi_writel(tmp & 0x00000000ffffffffLL, diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 906f9b9d715..6af68146c34 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1016,7 +1016,7 @@ static int i2c_pxa_probe(struct platform_device *dev) snprintf(i2c->adap.name, sizeof(i2c->adap.name), "pxa_i2c-i2c.%u", i2c->adap.nr); - i2c->clk = clk_get(&dev->dev, "I2CCLK"); + i2c->clk = clk_get(&dev->dev, NULL); if (IS_ERR(i2c->clk)) { ret = PTR_ERR(i2c->clk); goto eclk; @@ -1076,10 +1076,10 @@ static int i2c_pxa_probe(struct platform_device *dev) #ifdef CONFIG_I2C_PXA_SLAVE printk(KERN_INFO "I2C: %s: PXA I2C adapter, slave address %d\n", - i2c->adap.dev.bus_id, i2c->slave_addr); + dev_name(&i2c->adap.dev), i2c->slave_addr); #else printk(KERN_INFO "I2C: %s: PXA I2C adapter\n", - i2c->adap.dev.bus_id); + dev_name(&i2c->adap.dev)); #endif return 0; diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 3625ac8a3c5..90178a9af5a 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -923,7 +923,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2c); - dev_info(&pdev->dev, "%s: S3C I2C adapter\n", i2c->adap.dev.bus_id); + dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev)); return 0; err_cpufreq: diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c index 5e0e254976d..baa28b73ae4 100644 --- a/drivers/i2c/busses/i2c-sh7760.c +++ b/drivers/i2c/busses/i2c-sh7760.c @@ -475,7 +475,7 @@ static int __devinit sh7760_i2c_probe(struct platform_device *pdev) id->adap.nr = pdev->id; id->adap.algo = &sh7760_i2c_algo; - id->adap.class = I2C_CLASS_ALL; + id->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; id->adap.retries = 3; id->adap.algo_data = id; id->adap.dev.parent = &pdev->dev; diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 640cbb23732..1c01083b01b 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -160,9 +160,39 @@ struct sh_mobile_i2c_data { static void activate_ch(struct sh_mobile_i2c_data *pd) { + unsigned long i2c_clk; + u_int32_t num; + u_int32_t denom; + u_int32_t tmp; + /* Make sure the clock is enabled */ clk_enable(pd->clk); + /* Get clock rate after clock is enabled */ + i2c_clk = clk_get_rate(pd->clk); + + /* Calculate the value for iccl. From the data sheet: + * iccl = (p clock / transfer rate) * (L / (L + H)) + * where L and H are the SCL low/high ratio (5/4 in this case). + * We also round off the result. + */ + num = i2c_clk * 5; + denom = NORMAL_SPEED * 9; + tmp = num * 10 / denom; + if (tmp % 10 >= 5) + pd->iccl = (u_int8_t)((num/denom) + 1); + else + pd->iccl = (u_int8_t)(num/denom); + + /* Calculate the value for icch. From the data sheet: + icch = (p clock / transfer rate) * (H / (L + H)) */ + num = i2c_clk * 4; + tmp = num * 10 / denom; + if (tmp % 10 >= 5) + pd->icch = (u_int8_t)((num/denom) + 1); + else + pd->icch = (u_int8_t)(num/denom); + /* Enable channel and configure rx ack */ iowrite8(ioread8(ICCR(pd)) | ICCR_ICE, ICCR(pd)); @@ -318,7 +348,8 @@ static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd) } else data = i2c_op(pd, OP_RX, 0); - pd->msg->buf[real_pos] = data; + if (real_pos >= 0) + pd->msg->buf[real_pos] = data; } while (0); pd->pos++; @@ -458,40 +489,6 @@ static struct i2c_algorithm sh_mobile_i2c_algorithm = { .master_xfer = sh_mobile_i2c_xfer, }; -static void sh_mobile_i2c_setup_channel(struct platform_device *dev) -{ - struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev); - unsigned long peripheral_clk = clk_get_rate(pd->clk); - u_int32_t num; - u_int32_t denom; - u_int32_t tmp; - - spin_lock_init(&pd->lock); - init_waitqueue_head(&pd->wait); - - /* Calculate the value for iccl. From the data sheet: - * iccl = (p clock / transfer rate) * (L / (L + H)) - * where L and H are the SCL low/high ratio (5/4 in this case). - * We also round off the result. - */ - num = peripheral_clk * 5; - denom = NORMAL_SPEED * 9; - tmp = num * 10 / denom; - if (tmp % 10 >= 5) - pd->iccl = (u_int8_t)((num/denom) + 1); - else - pd->iccl = (u_int8_t)(num/denom); - - /* Calculate the value for icch. From the data sheet: - icch = (p clock / transfer rate) * (H / (L + H)) */ - num = peripheral_clk * 4; - tmp = num * 10 / denom; - if (tmp % 10 >= 5) - pd->icch = (u_int8_t)((num/denom) + 1); - else - pd->icch = (u_int8_t)(num/denom); -} - static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook) { struct resource *res; @@ -503,7 +500,7 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook) while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) { for (n = res->start; hook && n <= res->end; n++) { if (request_irq(n, sh_mobile_i2c_isr, IRQF_DISABLED, - dev->dev.bus_id, dev)) + dev_name(&dev->dev), dev)) goto rollback; } k++; @@ -532,6 +529,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) struct sh_mobile_i2c_data *pd; struct i2c_adapter *adap; struct resource *res; + char clk_name[8]; int size; int ret; @@ -541,9 +539,10 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) return -ENOMEM; } - pd->clk = clk_get(&dev->dev, "peripheral_clk"); + snprintf(clk_name, sizeof(clk_name), "i2c%d", dev->id); + pd->clk = clk_get(&dev->dev, clk_name); if (IS_ERR(pd->clk)) { - dev_err(&dev->dev, "cannot get peripheral clock\n"); + dev_err(&dev->dev, "cannot get clock \"%s\"\n", clk_name); ret = PTR_ERR(pd->clk); goto err; } @@ -585,7 +584,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) strlcpy(adap->name, dev->name, sizeof(adap->name)); - sh_mobile_i2c_setup_channel(dev); + spin_lock_init(&pd->lock); + init_waitqueue_head(&pd->wait); ret = i2c_add_numbered_adapter(adap); if (ret < 0) { diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index dfc2d5eb6a6..8ce2daff985 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -389,8 +389,8 @@ static int __devinit sis5595_probe(struct pci_dev *dev, const struct pci_device_ /* set up the sysfs linkage to our parent device */ sis5595_adapter.dev.parent = &dev->dev; - sprintf(sis5595_adapter.name, "SMBus SIS5595 adapter at %04x", - sis5595_base + SMB_INDEX); + snprintf(sis5595_adapter.name, sizeof(sis5595_adapter.name), + "SMBus SIS5595 adapter at %04x", sis5595_base + SMB_INDEX); err = i2c_add_adapter(&sis5595_adapter); if (err) { release_region(sis5595_base + SMB_INDEX, 2); diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index e7c4b790da5..9c9c016ff2b 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -487,8 +487,8 @@ static int __devinit sis630_probe(struct pci_dev *dev, const struct pci_device_i /* set up the sysfs linkage to our parent device */ sis630_adapter.dev.parent = &dev->dev; - sprintf(sis630_adapter.name, "SMBus SIS630 adapter at %04x", - acpi_base + SMB_STS); + snprintf(sis630_adapter.name, sizeof(sis630_adapter.name), + "SMBus SIS630 adapter at %04x", acpi_base + SMB_STS); return i2c_add_adapter(&sis630_adapter); } diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 0cbbdaee10e..cc025b22235 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -124,31 +124,6 @@ config SENSORS_PCF8591 These devices are hard to detect and rarely found on mainstream hardware. If unsure, say N. -config ISP1301_OMAP - tristate "Philips ISP1301 with OMAP OTG" - depends on ARCH_OMAP_OTG - help - If you say yes here you get support for the Philips ISP1301 - USB-On-The-Go transceiver working with the OMAP OTG controller. - The ISP1301 is used in products including H2 and H3 development - boards for Texas Instruments OMAP processors. - - This driver can also be built as a module. If so, the module - will be called isp1301_omap. - -config TPS65010 - tristate "TPS6501x Power Management chips" - depends on GPIOLIB - 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 - Power Management chips. These include voltage regulators, - lithium ion/polymer battery charging, and other features that - are often used in portable devices like cell phones and cameras. - - This driver can also be built as a module. If so, the module - will be called tps65010. - config SENSORS_MAX6875 tristate "Maxim MAX6875 Power supply supervisor" depends on EXPERIMENTAL @@ -174,37 +149,6 @@ config SENSORS_TSL2550 This driver can also be built as a module. If so, the module will be called tsl2550. -config MENELAUS - bool "TWL92330/Menelaus PM chip" - depends on I2C=y && ARCH_OMAP24XX - help - If you say yes here you get support for the Texas Instruments - TWL92330/Menelaus Power Management chip. This include voltage - regulators, Dual slot memory card tranceivers, real-time clock - and other features that are often used in portable devices like - cell phones and PDAs. - -config MCU_MPC8349EMITX - tristate "MPC8349E-mITX MCU driver" - depends on I2C && PPC_83xx - select GENERIC_GPIO - select ARCH_REQUIRE_GPIOLIB - help - Say Y here to enable soft power-off functionality on the Freescale - boards with the MPC8349E-mITX-compatible MCU chips. This driver will - also register MCU GPIOs with the generic GPIO API, so you'll able - to use MCU pins as GPIOs. - -config SENSORS_TSL256X - tristate "Texas TSL256X Ambient Light Sensor" - depends on I2C - help - If you say yes here you get support for the Texas TSL256X - ambient light sensor chip. - - This driver can also be built as a module. If so, the module - will be called tsl256x. - config PCA9632 tristate "Philips/NXP PCA9632 low power LED driver" depends on I2C diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index f060b2ef17c..a575282cd9e 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -19,12 +19,7 @@ obj-$(CONFIG_SENSORS_PCF50606) += pcf50606.o obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o obj-$(CONFIG_PCF8575) += pcf8575.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o -obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o -obj-$(CONFIG_TPS65010) += tps65010.o -obj-$(CONFIG_MENELAUS) += menelaus.o obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o -obj-$(CONFIG_MCU_MPC8349EMITX) += mcu_mpc8349emitx.o -obj-$(CONFIG_SENSORS_TSL256X) += tsl256x.o obj-$(CONFIG_PCA9632) += pca9632.o ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c deleted file mode 100644 index 28902ebd553..00000000000 --- a/drivers/i2c/chips/isp1301_omap.c +++ /dev/null @@ -1,1654 +0,0 @@ -/* - * isp1301_omap - ISP 1301 USB transceiver, talking to OMAP OTG controller - * - * Copyright (C) 2004 Texas Instruments - * Copyright (C) 2004 David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -#ifndef DEBUG -#undef VERBOSE -#endif - - -#define DRIVER_VERSION "24 August 2004" -#define DRIVER_NAME (isp1301_driver.driver.name) - -MODULE_DESCRIPTION("ISP1301 USB OTG Transceiver Driver"); -MODULE_LICENSE("GPL"); - -struct isp1301 { - struct otg_transceiver otg; - struct i2c_client *client; - void (*i2c_release)(struct device *dev); - - int irq_type; - - u32 last_otg_ctrl; - unsigned working:1; - - struct timer_list timer; - - /* use keventd context to change the state for us */ - struct work_struct work; - - unsigned long todo; -# define WORK_UPDATE_ISP 0 /* update ISP from OTG */ -# define WORK_UPDATE_OTG 1 /* update OTG from ISP */ -# define WORK_HOST_RESUME 4 /* resume host */ -# define WORK_TIMER 6 /* timer fired */ -# define WORK_STOP 7 /* don't resubmit */ -}; - - -/* bits in OTG_CTRL */ - -#define OTG_XCEIV_OUTPUTS \ - (OTG_ASESSVLD|OTG_BSESSEND|OTG_BSESSVLD|OTG_VBUSVLD|OTG_ID) -#define OTG_XCEIV_INPUTS \ - (OTG_PULLDOWN|OTG_PULLUP|OTG_DRV_VBUS|OTG_PD_VBUS|OTG_PU_VBUS|OTG_PU_ID) -#define OTG_CTRL_BITS \ - (OTG_A_BUSREQ|OTG_A_SETB_HNPEN|OTG_B_BUSREQ|OTG_B_HNPEN|OTG_BUSDROP) - /* and OTG_PULLUP is sometimes written */ - -#define OTG_CTRL_MASK (OTG_DRIVER_SEL| \ - OTG_XCEIV_OUTPUTS|OTG_XCEIV_INPUTS| \ - OTG_CTRL_BITS) - - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_MACH_OMAP_H2 - -/* board-specific PM hooks */ - -#include -#include -#include - - -#if defined(CONFIG_TPS65010) || defined(CONFIG_TPS65010_MODULE) - -#include - -#else - -static inline int tps65010_set_vbus_draw(unsigned mA) -{ - pr_debug("tps65010: draw %d mA (STUB)\n", mA); - return 0; -} - -#endif - -static void enable_vbus_draw(struct isp1301 *isp, unsigned mA) -{ - int status = tps65010_set_vbus_draw(mA); - if (status < 0) - pr_debug(" VBUS %d mA error %d\n", mA, status); -} - -static void enable_vbus_source(struct isp1301 *isp) -{ - /* this board won't supply more than 8mA vbus power. - * some boards can switch a 100ma "unit load" (or more). - */ -} - - -/* products will deliver OTG messages with LEDs, GUI, etc */ -static inline void notresponding(struct isp1301 *isp) -{ - printk(KERN_NOTICE "OTG device not responding.\n"); -} - - -#endif - -/*-------------------------------------------------------------------------*/ - -static struct i2c_driver isp1301_driver; - -/* smbus apis are used for portability */ - -static inline u8 -isp1301_get_u8(struct isp1301 *isp, u8 reg) -{ - return i2c_smbus_read_byte_data(isp->client, reg + 0); -} - -static inline int -isp1301_get_u16(struct isp1301 *isp, u8 reg) -{ - return i2c_smbus_read_word_data(isp->client, reg); -} - -static inline int -isp1301_set_bits(struct isp1301 *isp, u8 reg, u8 bits) -{ - return i2c_smbus_write_byte_data(isp->client, reg + 0, bits); -} - -static inline int -isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits) -{ - return i2c_smbus_write_byte_data(isp->client, reg + 1, bits); -} - -/*-------------------------------------------------------------------------*/ - -/* identification */ -#define ISP1301_VENDOR_ID 0x00 /* u16 read */ -#define ISP1301_PRODUCT_ID 0x02 /* u16 read */ -#define ISP1301_BCD_DEVICE 0x14 /* u16 read */ - -#define I2C_VENDOR_ID_PHILIPS 0x04cc -#define I2C_PRODUCT_ID_PHILIPS_1301 0x1301 - -/* operational registers */ -#define ISP1301_MODE_CONTROL_1 0x04 /* u8 read, set, +1 clear */ -# define MC1_SPEED (1 << 0) -# define MC1_SUSPEND (1 << 1) -# define MC1_DAT_SE0 (1 << 2) -# define MC1_TRANSPARENT (1 << 3) -# define MC1_BDIS_ACON_EN (1 << 4) -# define MC1_OE_INT_EN (1 << 5) -# define MC1_UART_EN (1 << 6) -# define MC1_MASK 0x7f -#define ISP1301_MODE_CONTROL_2 0x12 /* u8 read, set, +1 clear */ -# define MC2_GLOBAL_PWR_DN (1 << 0) -# define MC2_SPD_SUSP_CTRL (1 << 1) -# define MC2_BI_DI (1 << 2) -# define MC2_TRANSP_BDIR0 (1 << 3) -# define MC2_TRANSP_BDIR1 (1 << 4) -# define MC2_AUDIO_EN (1 << 5) -# define MC2_PSW_EN (1 << 6) -# define MC2_EN2V7 (1 << 7) -#define ISP1301_OTG_CONTROL_1 0x06 /* u8 read, set, +1 clear */ -# define OTG1_DP_PULLUP (1 << 0) -# define OTG1_DM_PULLUP (1 << 1) -# define OTG1_DP_PULLDOWN (1 << 2) -# define OTG1_DM_PULLDOWN (1 << 3) -# define OTG1_ID_PULLDOWN (1 << 4) -# define OTG1_VBUS_DRV (1 << 5) -# define OTG1_VBUS_DISCHRG (1 << 6) -# define OTG1_VBUS_CHRG (1 << 7) -#define ISP1301_OTG_STATUS 0x10 /* u8 readonly */ -# define OTG_B_SESS_END (1 << 6) -# define OTG_B_SESS_VLD (1 << 7) - -#define ISP1301_INTERRUPT_SOURCE 0x08 /* u8 read */ -#define ISP1301_INTERRUPT_LATCH 0x0A /* u8 read, set, +1 clear */ - -#define ISP1301_INTERRUPT_FALLING 0x0C /* u8 read, set, +1 clear */ -#define ISP1301_INTERRUPT_RISING 0x0E /* u8 read, set, +1 clear */ - -/* same bitfields in all interrupt registers */ -# define INTR_VBUS_VLD (1 << 0) -# define INTR_SESS_VLD (1 << 1) -# define INTR_DP_HI (1 << 2) -# define INTR_ID_GND (1 << 3) -# define INTR_DM_HI (1 << 4) -# define INTR_ID_FLOAT (1 << 5) -# define INTR_BDIS_ACON (1 << 6) -# define INTR_CR_INT (1 << 7) - -/*-------------------------------------------------------------------------*/ - -static const char *state_string(enum usb_otg_state state) -{ - switch (state) { - case OTG_STATE_A_IDLE: return "a_idle"; - case OTG_STATE_A_WAIT_VRISE: return "a_wait_vrise"; - case OTG_STATE_A_WAIT_BCON: return "a_wait_bcon"; - case OTG_STATE_A_HOST: return "a_host"; - case OTG_STATE_A_SUSPEND: return "a_suspend"; - case OTG_STATE_A_PERIPHERAL: return "a_peripheral"; - case OTG_STATE_A_WAIT_VFALL: return "a_wait_vfall"; - case OTG_STATE_A_VBUS_ERR: return "a_vbus_err"; - case OTG_STATE_B_IDLE: return "b_idle"; - case OTG_STATE_B_SRP_INIT: return "b_srp_init"; - case OTG_STATE_B_PERIPHERAL: return "b_peripheral"; - case OTG_STATE_B_WAIT_ACON: return "b_wait_acon"; - case OTG_STATE_B_HOST: return "b_host"; - default: return "UNDEFINED"; - } -} - -static inline const char *state_name(struct isp1301 *isp) -{ - return state_string(isp->otg.state); -} - -/*-------------------------------------------------------------------------*/ - -/* NOTE: some of this ISP1301 setup is specific to H2 boards; - * not everything is guarded by board-specific checks, or even using - * omap_usb_config data to deduce MC1_DAT_SE0 and MC2_BI_DI. - * - * ALSO: this currently doesn't use ISP1301 low-power modes - * while OTG is running. - */ - -static void power_down(struct isp1301 *isp) -{ - isp->otg.state = OTG_STATE_UNDEFINED; - - // isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN); - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND); - - isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_ID_PULLDOWN); - isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); -} - -static void power_up(struct isp1301 *isp) -{ - // isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN); - isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND); - - /* do this only when cpu is driving transceiver, - * so host won't see a low speed device... - */ - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); -} - -#define NO_HOST_SUSPEND - -static int host_suspend(struct isp1301 *isp) -{ -#ifdef NO_HOST_SUSPEND - return 0; -#else - struct device *dev; - - if (!isp->otg.host) - return -ENODEV; - - /* Currently ASSUMES only the OTG port matters; - * other ports could be active... - */ - dev = isp->otg.host->controller; - return dev->driver->suspend(dev, 3, 0); -#endif -} - -static int host_resume(struct isp1301 *isp) -{ -#ifdef NO_HOST_SUSPEND - return 0; -#else - struct device *dev; - - if (!isp->otg.host) - return -ENODEV; - - dev = isp->otg.host->controller; - return dev->driver->resume(dev, 0); -#endif -} - -static int gadget_suspend(struct isp1301 *isp) -{ - isp->otg.gadget->b_hnp_enable = 0; - isp->otg.gadget->a_hnp_support = 0; - isp->otg.gadget->a_alt_hnp_support = 0; - return usb_gadget_vbus_disconnect(isp->otg.gadget); -} - -/*-------------------------------------------------------------------------*/ - -#define TIMER_MINUTES 10 -#define TIMER_JIFFIES (TIMER_MINUTES * 60 * HZ) - -/* Almost all our I2C messaging comes from a work queue's task context. - * NOTE: guaranteeing certain response times might mean we shouldn't - * share keventd's work queue; a realtime task might be safest. - */ -void -isp1301_defer_work(struct isp1301 *isp, int work) -{ - int status; - - if (isp && !test_and_set_bit(work, &isp->todo)) { - (void) get_device(&isp->client->dev); - status = schedule_work(&isp->work); - if (!status && !isp->working) - dev_vdbg(&isp->client->dev, - "work item %d may be lost\n", work); - } -} - -/* called from irq handlers */ -static void a_idle(struct isp1301 *isp, const char *tag) -{ - u32 l; - - if (isp->otg.state == OTG_STATE_A_IDLE) - return; - - isp->otg.default_a = 1; - if (isp->otg.host) { - isp->otg.host->is_b_host = 0; - host_suspend(isp); - } - if (isp->otg.gadget) { - isp->otg.gadget->is_a_peripheral = 1; - gadget_suspend(isp); - } - isp->otg.state = OTG_STATE_A_IDLE; - l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS; - omap_writel(l, OTG_CTRL); - isp->last_otg_ctrl = l; - pr_debug(" --> %s/%s\n", state_name(isp), tag); -} - -/* called from irq handlers */ -static void b_idle(struct isp1301 *isp, const char *tag) -{ - u32 l; - - if (isp->otg.state == OTG_STATE_B_IDLE) - return; - - isp->otg.default_a = 0; - if (isp->otg.host) { - isp->otg.host->is_b_host = 1; - host_suspend(isp); - } - if (isp->otg.gadget) { - isp->otg.gadget->is_a_peripheral = 0; - gadget_suspend(isp); - } - isp->otg.state = OTG_STATE_B_IDLE; - l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS; - omap_writel(l, OTG_CTRL); - isp->last_otg_ctrl = l; - pr_debug(" --> %s/%s\n", state_name(isp), tag); -} - -static void -dump_regs(struct isp1301 *isp, const char *label) -{ -#ifdef DEBUG - u8 ctrl = isp1301_get_u8(isp, ISP1301_OTG_CONTROL_1); - u8 status = isp1301_get_u8(isp, ISP1301_OTG_STATUS); - u8 src = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE); - - pr_debug("otg: %06x, %s %s, otg/%02x stat/%02x.%02x\n", - omap_readl(OTG_CTRL), label, state_name(isp), - ctrl, status, src); - /* mode control and irq enables don't change much */ -#endif -} - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_USB_OTG - -/* - * The OMAP OTG controller handles most of the OTG state transitions. - * - * We translate isp1301 outputs (mostly voltage comparator status) into - * OTG inputs; OTG outputs (mostly pullup/pulldown controls) and HNP state - * flags into isp1301 inputs ... and infer state transitions. - */ - -#ifdef VERBOSE - -static void check_state(struct isp1301 *isp, const char *tag) -{ - enum usb_otg_state state = OTG_STATE_UNDEFINED; - u8 fsm = omap_readw(OTG_TEST) & 0x0ff; - unsigned extra = 0; - - switch (fsm) { - - /* default-b */ - case 0x0: - state = OTG_STATE_B_IDLE; - break; - case 0x3: - case 0x7: - extra = 1; - case 0x1: - state = OTG_STATE_B_PERIPHERAL; - break; - case 0x11: - state = OTG_STATE_B_SRP_INIT; - break; - - /* extra dual-role default-b states */ - case 0x12: - case 0x13: - case 0x16: - extra = 1; - case 0x17: - state = OTG_STATE_B_WAIT_ACON; - break; - case 0x34: - state = OTG_STATE_B_HOST; - break; - - /* default-a */ - case 0x36: - state = OTG_STATE_A_IDLE; - break; - case 0x3c: - state = OTG_STATE_A_WAIT_VFALL; - break; - case 0x7d: - state = OTG_STATE_A_VBUS_ERR; - break; - case 0x9e: - case 0x9f: - extra = 1; - case 0x89: - state = OTG_STATE_A_PERIPHERAL; - break; - case 0xb7: - state = OTG_STATE_A_WAIT_VRISE; - break; - case 0xb8: - state = OTG_STATE_A_WAIT_BCON; - break; - case 0xb9: - state = OTG_STATE_A_HOST; - break; - case 0xba: - state = OTG_STATE_A_SUSPEND; - break; - default: - break; - } - if (isp->otg.state == state && !extra) - return; - pr_debug("otg: %s FSM %s/%02x, %s, %06x\n", tag, - state_string(state), fsm, state_name(isp), - omap_readl(OTG_CTRL)); -} - -#else - -static inline void check_state(struct isp1301 *isp, const char *tag) { } - -#endif - -/* outputs from ISP1301_INTERRUPT_SOURCE */ -static void update_otg1(struct isp1301 *isp, u8 int_src) -{ - u32 otg_ctrl; - - otg_ctrl = omap_readl(OTG_CTRL) & OTG_CTRL_MASK; - otg_ctrl &= ~OTG_XCEIV_INPUTS; - otg_ctrl &= ~(OTG_ID|OTG_ASESSVLD|OTG_VBUSVLD); - - - if (int_src & INTR_SESS_VLD) - otg_ctrl |= OTG_ASESSVLD; - else if (isp->otg.state == OTG_STATE_A_WAIT_VFALL) { - a_idle(isp, "vfall"); - otg_ctrl &= ~OTG_CTRL_BITS; - } - if (int_src & INTR_VBUS_VLD) - otg_ctrl |= OTG_VBUSVLD; - if (int_src & INTR_ID_GND) { /* default-A */ - if (isp->otg.state == OTG_STATE_B_IDLE - || isp->otg.state == OTG_STATE_UNDEFINED) { - a_idle(isp, "init"); - return; - } - } else { /* default-B */ - otg_ctrl |= OTG_ID; - if (isp->otg.state == OTG_STATE_A_IDLE - || isp->otg.state == OTG_STATE_UNDEFINED) { - b_idle(isp, "init"); - return; - } - } - omap_writel(otg_ctrl, OTG_CTRL); -} - -/* outputs from ISP1301_OTG_STATUS */ -static void update_otg2(struct isp1301 *isp, u8 otg_status) -{ - u32 otg_ctrl; - - otg_ctrl = omap_readl(OTG_CTRL) & OTG_CTRL_MASK; - otg_ctrl &= ~OTG_XCEIV_INPUTS; - otg_ctrl &= ~(OTG_BSESSVLD | OTG_BSESSEND); - if (otg_status & OTG_B_SESS_VLD) - otg_ctrl |= OTG_BSESSVLD; - else if (otg_status & OTG_B_SESS_END) - otg_ctrl |= OTG_BSESSEND; - omap_writel(otg_ctrl, OTG_CTRL); -} - -/* inputs going to ISP1301 */ -static void otg_update_isp(struct isp1301 *isp) -{ - u32 otg_ctrl, otg_change; - u8 set = OTG1_DM_PULLDOWN, clr = OTG1_DM_PULLUP; - - otg_ctrl = omap_readl(OTG_CTRL); - otg_change = otg_ctrl ^ isp->last_otg_ctrl; - isp->last_otg_ctrl = otg_ctrl; - otg_ctrl = otg_ctrl & OTG_XCEIV_INPUTS; - - switch (isp->otg.state) { - case OTG_STATE_B_IDLE: - case OTG_STATE_B_PERIPHERAL: - case OTG_STATE_B_SRP_INIT: - if (!(otg_ctrl & OTG_PULLUP)) { - // if (otg_ctrl & OTG_B_HNPEN) { - if (isp->otg.gadget->b_hnp_enable) { - isp->otg.state = OTG_STATE_B_WAIT_ACON; - pr_debug(" --> b_wait_acon\n"); - } - goto pulldown; - } -pullup: - set |= OTG1_DP_PULLUP; - clr |= OTG1_DP_PULLDOWN; - break; - case OTG_STATE_A_SUSPEND: - case OTG_STATE_A_PERIPHERAL: - if (otg_ctrl & OTG_PULLUP) - goto pullup; - /* FALLTHROUGH */ - // case OTG_STATE_B_WAIT_ACON: - default: -pulldown: - set |= OTG1_DP_PULLDOWN; - clr |= OTG1_DP_PULLUP; - break; - } - -# define toggle(OTG,ISP) do { \ - if (otg_ctrl & OTG) set |= ISP; \ - else clr |= ISP; \ - } while (0) - - if (!(isp->otg.host)) - otg_ctrl &= ~OTG_DRV_VBUS; - - switch (isp->otg.state) { - case OTG_STATE_A_SUSPEND: - if (otg_ctrl & OTG_DRV_VBUS) { - set |= OTG1_VBUS_DRV; - break; - } - /* HNP failed for some reason (A_AIDL_BDIS timeout) */ - notresponding(isp); - - /* FALLTHROUGH */ - case OTG_STATE_A_VBUS_ERR: - isp->otg.state = OTG_STATE_A_WAIT_VFALL; - pr_debug(" --> a_wait_vfall\n"); - /* FALLTHROUGH */ - case OTG_STATE_A_WAIT_VFALL: - /* FIXME usbcore thinks port power is still on ... */ - clr |= OTG1_VBUS_DRV; - break; - case OTG_STATE_A_IDLE: - if (otg_ctrl & OTG_DRV_VBUS) { - isp->otg.state = OTG_STATE_A_WAIT_VRISE; - pr_debug(" --> a_wait_vrise\n"); - } - /* FALLTHROUGH */ - default: - toggle(OTG_DRV_VBUS, OTG1_VBUS_DRV); - } - - toggle(OTG_PU_VBUS, OTG1_VBUS_CHRG); - toggle(OTG_PD_VBUS, OTG1_VBUS_DISCHRG); - -# undef toggle - - isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, set); - isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, clr); - - /* HNP switch to host or peripheral; and SRP */ - if (otg_change & OTG_PULLUP) { - u32 l; - - switch (isp->otg.state) { - case OTG_STATE_B_IDLE: - if (clr & OTG1_DP_PULLUP) - break; - isp->otg.state = OTG_STATE_B_PERIPHERAL; - pr_debug(" --> b_peripheral\n"); - break; - case OTG_STATE_A_SUSPEND: - if (clr & OTG1_DP_PULLUP) - break; - isp->otg.state = OTG_STATE_A_PERIPHERAL; - pr_debug(" --> a_peripheral\n"); - break; - default: - break; - } - l = omap_readl(OTG_CTRL); - l |= OTG_PULLUP; - omap_writel(l, OTG_CTRL); - } - - check_state(isp, __func__); - dump_regs(isp, "otg->isp1301"); -} - -static irqreturn_t omap_otg_irq(int irq, void *_isp) -{ - u16 otg_irq = omap_readw(OTG_IRQ_SRC); - u32 otg_ctrl; - int ret = IRQ_NONE; - struct isp1301 *isp = _isp; - - /* update ISP1301 transciever from OTG controller */ - if (otg_irq & OPRT_CHG) { - omap_writew(OPRT_CHG, OTG_IRQ_SRC); - isp1301_defer_work(isp, WORK_UPDATE_ISP); - ret = IRQ_HANDLED; - - /* SRP to become b_peripheral failed */ - } else if (otg_irq & B_SRP_TMROUT) { - pr_debug("otg: B_SRP_TIMEOUT, %06x\n", omap_readl(OTG_CTRL)); - notresponding(isp); - - /* gadget drivers that care should monitor all kinds of - * remote wakeup (SRP, normal) using their own timer - * to give "check cable and A-device" messages. - */ - if (isp->otg.state == OTG_STATE_B_SRP_INIT) - b_idle(isp, "srp_timeout"); - - omap_writew(B_SRP_TMROUT, OTG_IRQ_SRC); - ret = IRQ_HANDLED; - - /* HNP to become b_host failed */ - } else if (otg_irq & B_HNP_FAIL) { - pr_debug("otg: %s B_HNP_FAIL, %06x\n", - state_name(isp), omap_readl(OTG_CTRL)); - notresponding(isp); - - otg_ctrl = omap_readl(OTG_CTRL); - otg_ctrl |= OTG_BUSDROP; - otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; - omap_writel(otg_ctrl, OTG_CTRL); - - /* subset of b_peripheral()... */ - isp->otg.state = OTG_STATE_B_PERIPHERAL; - pr_debug(" --> b_peripheral\n"); - - omap_writew(B_HNP_FAIL, OTG_IRQ_SRC); - ret = IRQ_HANDLED; - - /* detect SRP from B-device ... */ - } else if (otg_irq & A_SRP_DETECT) { - pr_debug("otg: %s SRP_DETECT, %06x\n", - state_name(isp), omap_readl(OTG_CTRL)); - - isp1301_defer_work(isp, WORK_UPDATE_OTG); - switch (isp->otg.state) { - case OTG_STATE_A_IDLE: - if (!isp->otg.host) - break; - isp1301_defer_work(isp, WORK_HOST_RESUME); - otg_ctrl = omap_readl(OTG_CTRL); - otg_ctrl |= OTG_A_BUSREQ; - otg_ctrl &= ~(OTG_BUSDROP|OTG_B_BUSREQ) - & ~OTG_XCEIV_INPUTS - & OTG_CTRL_MASK; - omap_writel(otg_ctrl, OTG_CTRL); - break; - default: - break; - } - - omap_writew(A_SRP_DETECT, OTG_IRQ_SRC); - ret = IRQ_HANDLED; - - /* timer expired: T(a_wait_bcon) and maybe T(a_wait_vrise) - * we don't track them separately - */ - } else if (otg_irq & A_REQ_TMROUT) { - otg_ctrl = omap_readl(OTG_CTRL); - pr_info("otg: BCON_TMOUT from %s, %06x\n", - state_name(isp), otg_ctrl); - notresponding(isp); - - otg_ctrl |= OTG_BUSDROP; - otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; - omap_writel(otg_ctrl, OTG_CTRL); - isp->otg.state = OTG_STATE_A_WAIT_VFALL; - - omap_writew(A_REQ_TMROUT, OTG_IRQ_SRC); - ret = IRQ_HANDLED; - - /* A-supplied voltage fell too low; overcurrent */ - } else if (otg_irq & A_VBUS_ERR) { - otg_ctrl = omap_readl(OTG_CTRL); - printk(KERN_ERR "otg: %s, VBUS_ERR %04x ctrl %06x\n", - state_name(isp), otg_irq, otg_ctrl); - - otg_ctrl |= OTG_BUSDROP; - otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; - omap_writel(otg_ctrl, OTG_CTRL); - isp->otg.state = OTG_STATE_A_VBUS_ERR; - - omap_writew(A_VBUS_ERR, OTG_IRQ_SRC); - ret = IRQ_HANDLED; - - /* switch driver; the transciever code activates it, - * ungating the udc clock or resuming OHCI. - */ - } else if (otg_irq & DRIVER_SWITCH) { - int kick = 0; - - otg_ctrl = omap_readl(OTG_CTRL); - printk(KERN_NOTICE "otg: %s, SWITCH to %s, ctrl %06x\n", - state_name(isp), - (otg_ctrl & OTG_DRIVER_SEL) - ? "gadget" : "host", - otg_ctrl); - isp1301_defer_work(isp, WORK_UPDATE_ISP); - - /* role is peripheral */ - if (otg_ctrl & OTG_DRIVER_SEL) { - switch (isp->otg.state) { - case OTG_STATE_A_IDLE: - b_idle(isp, __func__); - break; - default: - break; - } - isp1301_defer_work(isp, WORK_UPDATE_ISP); - - /* role is host */ - } else { - if (!(otg_ctrl & OTG_ID)) { - otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; - omap_writel(otg_ctrl | OTG_A_BUSREQ, OTG_CTRL); - } - - if (isp->otg.host) { - switch (isp->otg.state) { - case OTG_STATE_B_WAIT_ACON: - isp->otg.state = OTG_STATE_B_HOST; - pr_debug(" --> b_host\n"); - kick = 1; - break; - case OTG_STATE_A_WAIT_BCON: - isp->otg.state = OTG_STATE_A_HOST; - pr_debug(" --> a_host\n"); - break; - case OTG_STATE_A_PERIPHERAL: - isp->otg.state = OTG_STATE_A_WAIT_BCON; - pr_debug(" --> a_wait_bcon\n"); - break; - default: - break; - } - isp1301_defer_work(isp, WORK_HOST_RESUME); - } - } - - omap_writew(DRIVER_SWITCH, OTG_IRQ_SRC); - ret = IRQ_HANDLED; - - if (kick) - usb_bus_start_enum(isp->otg.host, - isp->otg.host->otg_port); - } - - check_state(isp, __func__); - return ret; -} - -static struct platform_device *otg_dev; - -static int otg_init(struct isp1301 *isp) -{ - u32 l; - - if (!otg_dev) - return -ENODEV; - - dump_regs(isp, __func__); - /* some of these values are board-specific... */ - l = omap_readl(OTG_SYSCON_2); - l |= OTG_EN - /* for B-device: */ - | SRP_GPDATA /* 9msec Bdev D+ pulse */ - | SRP_GPDVBUS /* discharge after VBUS pulse */ - // | (3 << 24) /* 2msec VBUS pulse */ - /* for A-device: */ - | (0 << 20) /* 200ms nominal A_WAIT_VRISE timer */ - | SRP_DPW /* detect 167+ns SRP pulses */ - | SRP_DATA | SRP_VBUS /* accept both kinds of SRP pulse */ - ; - omap_writel(l, OTG_SYSCON_2); - - update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE)); - update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS)); - - check_state(isp, __func__); - pr_debug("otg: %s, %s %06x\n", - state_name(isp), __func__, omap_readl(OTG_CTRL)); - - omap_writew(DRIVER_SWITCH | OPRT_CHG - | B_SRP_TMROUT | B_HNP_FAIL - | A_VBUS_ERR | A_SRP_DETECT | A_REQ_TMROUT, OTG_IRQ_EN); - - l = omap_readl(OTG_SYSCON_2); - l |= OTG_EN; - omap_writel(l, OTG_SYSCON_2); - - return 0; -} - -static int otg_probe(struct platform_device *dev) -{ - // struct omap_usb_config *config = dev->platform_data; - - otg_dev = dev; - return 0; -} - -static int otg_remove(struct platform_device *dev) -{ - otg_dev = 0; - return 0; -} - -struct platform_driver omap_otg_driver = { - .probe = otg_probe, - .remove = otg_remove, - .driver = { - .owner = THIS_MODULE, - .name = "omap_otg", - }, -}; - -static int otg_bind(struct isp1301 *isp) -{ - int status; - - if (otg_dev) - return -EBUSY; - - status = platform_driver_register(&omap_otg_driver); - if (status < 0) - return status; - - if (otg_dev) - status = request_irq(otg_dev->resource[1].start, omap_otg_irq, - IRQF_DISABLED, DRIVER_NAME, isp); - else - status = -ENODEV; - - if (status < 0) - platform_driver_unregister(&omap_otg_driver); - return status; -} - -static void otg_unbind(struct isp1301 *isp) -{ - if (!otg_dev) - return; - free_irq(otg_dev->resource[1].start, isp); -} - -#else - -/* OTG controller isn't clocked */ - -#endif /* CONFIG_USB_OTG */ - -/*-------------------------------------------------------------------------*/ - -static void b_peripheral(struct isp1301 *isp) -{ - u32 l; - - l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS; - omap_writel(l, OTG_CTRL); - - usb_gadget_vbus_connect(isp->otg.gadget); - -#ifdef CONFIG_USB_OTG - enable_vbus_draw(isp, 8); - otg_update_isp(isp); -#else - enable_vbus_draw(isp, 100); - /* UDC driver just set OTG_BSESSVLD */ - isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLUP); - isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLDOWN); - isp->otg.state = OTG_STATE_B_PERIPHERAL; - pr_debug(" --> b_peripheral\n"); - dump_regs(isp, "2periph"); -#endif -} - -static void isp_update_otg(struct isp1301 *isp, u8 stat) -{ - u8 isp_stat, isp_bstat; - enum usb_otg_state state = isp->otg.state; - - if (stat & INTR_BDIS_ACON) - pr_debug("OTG: BDIS_ACON, %s\n", state_name(isp)); - - /* start certain state transitions right away */ - isp_stat = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE); - if (isp_stat & INTR_ID_GND) { - if (isp->otg.default_a) { - switch (state) { - case OTG_STATE_B_IDLE: - a_idle(isp, "idle"); - /* FALLTHROUGH */ - case OTG_STATE_A_IDLE: - enable_vbus_source(isp); - /* FALLTHROUGH */ - case OTG_STATE_A_WAIT_VRISE: - /* we skip over OTG_STATE_A_WAIT_BCON, since - * the HC will transition to A_HOST (or - * A_SUSPEND!) without our noticing except - * when HNP is used. - */ - if (isp_stat & INTR_VBUS_VLD) - isp->otg.state = OTG_STATE_A_HOST; - break; - case OTG_STATE_A_WAIT_VFALL: - if (!(isp_stat & INTR_SESS_VLD)) - a_idle(isp, "vfell"); - break; - default: - if (!(isp_stat & INTR_VBUS_VLD)) - isp->otg.state = OTG_STATE_A_VBUS_ERR; - break; - } - isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS); - } else { - switch (state) { - case OTG_STATE_B_PERIPHERAL: - case OTG_STATE_B_HOST: - case OTG_STATE_B_WAIT_ACON: - usb_gadget_vbus_disconnect(isp->otg.gadget); - break; - default: - break; - } - if (state != OTG_STATE_A_IDLE) - a_idle(isp, "id"); - if (isp->otg.host && state == OTG_STATE_A_IDLE) - isp1301_defer_work(isp, WORK_HOST_RESUME); - isp_bstat = 0; - } - } else { - u32 l; - - /* if user unplugged mini-A end of cable, - * don't bypass A_WAIT_VFALL. - */ - if (isp->otg.default_a) { - switch (state) { - default: - isp->otg.state = OTG_STATE_A_WAIT_VFALL; - break; - case OTG_STATE_A_WAIT_VFALL: - state = OTG_STATE_A_IDLE; - /* khubd may take a while to notice and - * handle this disconnect, so don't go - * to B_IDLE quite yet. - */ - break; - case OTG_STATE_A_IDLE: - host_suspend(isp); - isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, - MC1_BDIS_ACON_EN); - isp->otg.state = OTG_STATE_B_IDLE; - l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK; - l &= ~OTG_CTRL_BITS; - omap_writel(l, OTG_CTRL); - break; - case OTG_STATE_B_IDLE: - break; - } - } - isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS); - - switch (isp->otg.state) { - case OTG_STATE_B_PERIPHERAL: - case OTG_STATE_B_WAIT_ACON: - case OTG_STATE_B_HOST: - if (likely(isp_bstat & OTG_B_SESS_VLD)) - break; - enable_vbus_draw(isp, 0); -#ifndef CONFIG_USB_OTG - /* UDC driver will clear OTG_BSESSVLD */ - isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, - OTG1_DP_PULLDOWN); - isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, - OTG1_DP_PULLUP); - dump_regs(isp, __func__); -#endif - /* FALLTHROUGH */ - case OTG_STATE_B_SRP_INIT: - b_idle(isp, __func__); - l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS; - omap_writel(l, OTG_CTRL); - /* FALLTHROUGH */ - case OTG_STATE_B_IDLE: - if (isp->otg.gadget && (isp_bstat & OTG_B_SESS_VLD)) { -#ifdef CONFIG_USB_OTG - update_otg1(isp, isp_stat); - update_otg2(isp, isp_bstat); -#endif - b_peripheral(isp); - } else if (!(isp_stat & (INTR_VBUS_VLD|INTR_SESS_VLD))) - isp_bstat |= OTG_B_SESS_END; - break; - case OTG_STATE_A_WAIT_VFALL: - break; - default: - pr_debug("otg: unsupported b-device %s\n", - state_name(isp)); - break; - } - } - - if (state != isp->otg.state) - pr_debug(" isp, %s -> %s\n", - state_string(state), state_name(isp)); - -#ifdef CONFIG_USB_OTG - /* update the OTG controller state to match the isp1301; may - * trigger OPRT_CHG irqs for changes going to the isp1301. - */ - update_otg1(isp, isp_stat); - update_otg2(isp, isp_bstat); - check_state(isp, __func__); -#endif - - dump_regs(isp, "isp1301->otg"); -} - -/*-------------------------------------------------------------------------*/ - -static u8 isp1301_clear_latch(struct isp1301 *isp) -{ - u8 latch = isp1301_get_u8(isp, ISP1301_INTERRUPT_LATCH); - isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, latch); - return latch; -} - -static void -isp1301_work(struct work_struct *work) -{ - struct isp1301 *isp = container_of(work, struct isp1301, work); - int stop; - - /* implicit lock: we're the only task using this device */ - isp->working = 1; - do { - stop = test_bit(WORK_STOP, &isp->todo); - -#ifdef CONFIG_USB_OTG - /* transfer state from otg engine to isp1301 */ - if (test_and_clear_bit(WORK_UPDATE_ISP, &isp->todo)) { - otg_update_isp(isp); - put_device(&isp->client->dev); - } -#endif - /* transfer state from isp1301 to otg engine */ - if (test_and_clear_bit(WORK_UPDATE_OTG, &isp->todo)) { - u8 stat = isp1301_clear_latch(isp); - - isp_update_otg(isp, stat); - put_device(&isp->client->dev); - } - - if (test_and_clear_bit(WORK_HOST_RESUME, &isp->todo)) { - u32 otg_ctrl; - - /* - * skip A_WAIT_VRISE; hc transitions invisibly - * skip A_WAIT_BCON; same. - */ - switch (isp->otg.state) { - case OTG_STATE_A_WAIT_BCON: - case OTG_STATE_A_WAIT_VRISE: - isp->otg.state = OTG_STATE_A_HOST; - pr_debug(" --> a_host\n"); - otg_ctrl = omap_readl(OTG_CTRL); - otg_ctrl |= OTG_A_BUSREQ; - otg_ctrl &= ~(OTG_BUSDROP|OTG_B_BUSREQ) - & OTG_CTRL_MASK; - omap_writel(otg_ctrl, OTG_CTRL); - break; - case OTG_STATE_B_WAIT_ACON: - isp->otg.state = OTG_STATE_B_HOST; - pr_debug(" --> b_host (acon)\n"); - break; - case OTG_STATE_B_HOST: - case OTG_STATE_B_IDLE: - case OTG_STATE_A_IDLE: - break; - default: - pr_debug(" host resume in %s\n", - state_name(isp)); - } - host_resume(isp); - // mdelay(10); - put_device(&isp->client->dev); - } - - if (test_and_clear_bit(WORK_TIMER, &isp->todo)) { -#ifdef VERBOSE - dump_regs(isp, "timer"); - if (!stop) - mod_timer(&isp->timer, jiffies + TIMER_JIFFIES); -#endif - put_device(&isp->client->dev); - } - - if (isp->todo) - dev_vdbg(&isp->client->dev, - "work done, todo = 0x%lx\n", - isp->todo); - if (stop) { - dev_dbg(&isp->client->dev, "stop\n"); - break; - } - } while (isp->todo); - isp->working = 0; -} - -static irqreturn_t isp1301_irq(int irq, void *isp) -{ - isp1301_defer_work(isp, WORK_UPDATE_OTG); - return IRQ_HANDLED; -} - -static void isp1301_timer(unsigned long _isp) -{ - isp1301_defer_work((void *)_isp, WORK_TIMER); -} - -/*-------------------------------------------------------------------------*/ - -static void isp1301_release(struct device *dev) -{ - struct isp1301 *isp; - - isp = dev_get_drvdata(dev); - - /* ugly -- i2c hijacks our memory hook to wait_for_completion() */ - if (isp->i2c_release) - isp->i2c_release(dev); - kfree (isp); -} - -static struct isp1301 *the_transceiver; - -static int __exit isp1301_remove(struct i2c_client *i2c) -{ - struct isp1301 *isp; - - isp = i2c_get_clientdata(i2c); - - isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0); - isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0); - free_irq(i2c->irq, isp); -#ifdef CONFIG_USB_OTG - otg_unbind(isp); -#endif - if (machine_is_omap_h2()) - omap_free_gpio(2); - - isp->timer.data = 0; - set_bit(WORK_STOP, &isp->todo); - del_timer_sync(&isp->timer); - flush_scheduled_work(); - - put_device(&i2c->dev); - the_transceiver = 0; - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* NOTE: three modes are possible here, only one of which - * will be standards-conformant on any given system: - * - * - OTG mode (dual-role), required if there's a Mini-AB connector - * - HOST mode, for when there's one or more A (host) connectors - * - DEVICE mode, for when there's a B/Mini-B (device) connector - * - * As a rule, you won't have an isp1301 chip unless it's there to - * support the OTG mode. Other modes help testing USB controllers - * in isolation from (full) OTG support, or maybe so later board - * revisions can help to support those feature. - */ - -#ifdef CONFIG_USB_OTG - -static int isp1301_otg_enable(struct isp1301 *isp) -{ - power_up(isp); - otg_init(isp); - - /* NOTE: since we don't change this, this provides - * a few more interrupts than are strictly needed. - */ - isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, - INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND); - isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, - INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND); - - dev_info(&isp->client->dev, "ready for dual-role USB ...\n"); - - return 0; -} - -#endif - -/* add or disable the host device+driver */ -static int -isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host) -{ - struct isp1301 *isp = container_of(otg, struct isp1301, otg); - - if (!otg || isp != the_transceiver) - return -ENODEV; - - if (!host) { - omap_writew(0, OTG_IRQ_EN); - power_down(isp); - isp->otg.host = 0; - return 0; - } - -#ifdef CONFIG_USB_OTG - isp->otg.host = host; - dev_dbg(&isp->client->dev, "registered host\n"); - host_suspend(isp); - if (isp->otg.gadget) - return isp1301_otg_enable(isp); - return 0; - -#elif !defined(CONFIG_USB_GADGET_OMAP) - // FIXME update its refcount - isp->otg.host = host; - - power_up(isp); - - if (machine_is_omap_h2()) - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); - - dev_info(&isp->client->dev, "A-Host sessions ok\n"); - isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, - INTR_ID_GND); - isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, - INTR_ID_GND); - - /* If this has a Mini-AB connector, this mode is highly - * nonstandard ... but can be handy for testing, especially with - * the Mini-A end of an OTG cable. (Or something nonstandard - * like MiniB-to-StandardB, maybe built with a gender mender.) - */ - isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_VBUS_DRV); - - dump_regs(isp, __func__); - - return 0; - -#else - dev_dbg(&isp->client->dev, "host sessions not allowed\n"); - return -EINVAL; -#endif - -} - -static int -isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget) -{ - struct isp1301 *isp = container_of(otg, struct isp1301, otg); - u32 l; - - if (!otg || isp != the_transceiver) - return -ENODEV; - - if (!gadget) { - omap_writew(0, OTG_IRQ_EN); - if (!isp->otg.default_a) - enable_vbus_draw(isp, 0); - usb_gadget_vbus_disconnect(isp->otg.gadget); - isp->otg.gadget = 0; - power_down(isp); - return 0; - } - -#ifdef CONFIG_USB_OTG - isp->otg.gadget = gadget; - dev_dbg(&isp->client->dev, "registered gadget\n"); - /* gadget driver may be suspended until vbus_connect () */ - if (isp->otg.host) - return isp1301_otg_enable(isp); - return 0; - -#elif !defined(CONFIG_USB_OHCI_HCD) && !defined(CONFIG_USB_OHCI_HCD_MODULE) - isp->otg.gadget = gadget; - // FIXME update its refcount - - l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK; - l &= ~(OTG_XCEIV_OUTPUTS|OTG_CTRL_BITS); - l |= OTG_ID; - omap_writel(l, OTG_CTRL); - - power_up(isp); - isp->otg.state = OTG_STATE_B_IDLE; - - if (machine_is_omap_h2()) - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); - - isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, - INTR_SESS_VLD); - isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, - INTR_VBUS_VLD); - dev_info(&isp->client->dev, "B-Peripheral sessions ok\n"); - dump_regs(isp, __func__); - - /* If this has a Mini-AB connector, this mode is highly - * nonstandard ... but can be handy for testing, so long - * as you don't plug a Mini-A cable into the jack. - */ - if (isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE) & INTR_VBUS_VLD) - b_peripheral(isp); - - return 0; - -#else - dev_dbg(&isp->client->dev, "peripheral sessions not allowed\n"); - return -EINVAL; -#endif -} - - -/*-------------------------------------------------------------------------*/ - -static int -isp1301_set_power(struct otg_transceiver *dev, unsigned mA) -{ - if (!the_transceiver) - return -ENODEV; - if (dev->state == OTG_STATE_B_PERIPHERAL) - enable_vbus_draw(the_transceiver, mA); - return 0; -} - -static int -isp1301_start_srp(struct otg_transceiver *dev) -{ - struct isp1301 *isp = container_of(dev, struct isp1301, otg); - u32 otg_ctrl; - - if (!dev || isp != the_transceiver - || isp->otg.state != OTG_STATE_B_IDLE) - return -ENODEV; - - otg_ctrl = omap_readl(OTG_CTRL); - if (!(otg_ctrl & OTG_BSESSEND)) - return -EINVAL; - - otg_ctrl |= OTG_B_BUSREQ; - otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK; - omap_writel(otg_ctrl, OTG_CTRL); - isp->otg.state = OTG_STATE_B_SRP_INIT; - - pr_debug("otg: SRP, %s ... %06x\n", state_name(isp), - omap_readl(OTG_CTRL)); -#ifdef CONFIG_USB_OTG - check_state(isp, __func__); -#endif - return 0; -} - -static int -isp1301_start_hnp(struct otg_transceiver *dev) -{ -#ifdef CONFIG_USB_OTG - struct isp1301 *isp = container_of(dev, struct isp1301, otg); - u32 l; - - if (!dev || isp != the_transceiver) - return -ENODEV; - if (isp->otg.default_a && (isp->otg.host == NULL - || !isp->otg.host->b_hnp_enable)) - return -ENOTCONN; - if (!isp->otg.default_a && (isp->otg.gadget == NULL - || !isp->otg.gadget->b_hnp_enable)) - return -ENOTCONN; - - /* We want hardware to manage most HNP protocol timings. - * So do this part as early as possible... - */ - switch (isp->otg.state) { - case OTG_STATE_B_HOST: - isp->otg.state = OTG_STATE_B_PERIPHERAL; - /* caller will suspend next */ - break; - case OTG_STATE_A_HOST: -#if 0 - /* autoconnect mode avoids irq latency bugs */ - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, - MC1_BDIS_ACON_EN); -#endif - /* caller must suspend then clear A_BUSREQ */ - usb_gadget_vbus_connect(isp->otg.gadget); - l = omap_readl(OTG_CTRL); - l |= OTG_A_SETB_HNPEN; - omap_writel(l, OTG_CTRL); - - break; - case OTG_STATE_A_PERIPHERAL: - /* initiated by B-Host suspend */ - break; - default: - return -EILSEQ; - } - pr_debug("otg: HNP %s, %06x ...\n", - state_name(isp), omap_readl(OTG_CTRL)); - check_state(isp, __func__); - return 0; -#else - /* srp-only */ - return -EINVAL; -#endif -} - -/*-------------------------------------------------------------------------*/ - -static int __init isp1301_probe(struct i2c_client *i2c) -{ - int status; - struct isp1301 *isp; - - if (the_transceiver) - return 0; - - isp = kzalloc(sizeof *isp, GFP_KERNEL); - if (!isp) - return 0; - - INIT_WORK(&isp->work, isp1301_work); - init_timer(&isp->timer); - isp->timer.function = isp1301_timer; - isp->timer.data = (unsigned long) isp; - - i2c_set_clientdata(i2c, isp); - isp->client = i2c; - - /* verify the chip (shouldn't be necesary) */ - status = isp1301_get_u16(isp, ISP1301_VENDOR_ID); - if (status != I2C_VENDOR_ID_PHILIPS) { - dev_dbg(&i2c->dev, "not philips id: %d\n", status); - goto fail; - } - status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID); - if (status != I2C_PRODUCT_ID_PHILIPS_1301) { - dev_dbg(&i2c->dev, "not isp1301, %d\n", status); - goto fail; - } - isp->i2c_release = i2c->dev.release; - i2c->dev.release = isp1301_release; - - /* initial development used chiprev 2.00 */ - status = i2c_smbus_read_word_data(i2c, ISP1301_BCD_DEVICE); - dev_info(&i2c->dev, "chiprev %x.%02x, driver " DRIVER_VERSION "\n", - status >> 8, status & 0xff); - - /* make like power-on reset */ - isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_MASK); - - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_BI_DI); - isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, ~MC2_BI_DI); - - isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, - OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN); - isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, - ~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN)); - - isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, ~0); - isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0); - isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0); - -#ifdef CONFIG_USB_OTG - status = otg_bind(isp); - if (status < 0) { - dev_dbg(&i2c->dev, "can't bind OTG\n"); - goto fail; - } -#endif - - if (machine_is_omap_h2()) { - /* full speed signaling by default */ - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, - MC1_SPEED); - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, - MC2_SPD_SUSP_CTRL); - - /* IRQ wired at M14 */ - omap_cfg_reg(M14_1510_GPIO2); - if (gpio_request(2, "isp1301") == 0) - gpio_direction_input(2); - isp->irq_type = IRQF_TRIGGER_FALLING; - } - - isp->irq_type |= IRQF_SAMPLE_RANDOM; - status = request_irq(i2c->irq, isp1301_irq, - isp->irq_type, DRIVER_NAME, isp); - if (status < 0) { - dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n", - i2c->irq, status); - goto fail; - } - - isp->otg.dev = &i2c->dev; - isp->otg.label = DRIVER_NAME; - - isp->otg.set_host = isp1301_set_host, - isp->otg.set_peripheral = isp1301_set_peripheral, - isp->otg.set_power = isp1301_set_power, - isp->otg.start_srp = isp1301_start_srp, - isp->otg.start_hnp = isp1301_start_hnp, - - enable_vbus_draw(isp, 0); - power_down(isp); - the_transceiver = isp; - -#ifdef CONFIG_USB_OTG - update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE)); - update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS)); -#endif - - dump_regs(isp, __func__); - -#ifdef VERBOSE - mod_timer(&isp->timer, jiffies + TIMER_JIFFIES); - dev_dbg(&i2c->dev, "scheduled timer, %d min\n", TIMER_MINUTES); -#endif - - status = otg_set_transceiver(&isp->otg); - if (status < 0) - dev_err(&i2c->dev, "can't register transceiver, %d\n", - status); - - return 0; - -fail: - kfree(isp); - return -ENODEV; -} - -static const struct i2c_device_id isp1301_id[] = { - { "isp1301_omap", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, isp1301_id); - -static struct i2c_driver isp1301_driver = { - .driver = { - .name = "isp1301_omap", - }, - .probe = isp1301_probe, - .remove = __exit_p(isp1301_remove), - .id_table = isp1301_id, -}; - -/*-------------------------------------------------------------------------*/ - -static int __init isp_init(void) -{ - return i2c_add_driver(&isp1301_driver); -} -module_init(isp_init); - -static void __exit isp_exit(void) -{ - if (the_transceiver) - otg_set_transceiver(0); - i2c_del_driver(&isp1301_driver); -} -module_exit(isp_exit); - diff --git a/drivers/i2c/chips/mcu_mpc8349emitx.c b/drivers/i2c/chips/mcu_mpc8349emitx.c deleted file mode 100644 index 82a9bcb858b..00000000000 --- a/drivers/i2c/chips/mcu_mpc8349emitx.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Power Management and GPIO expander driver for MPC8349E-mITX-compatible MCU - * - * Copyright (c) 2008 MontaVista Software, Inc. - * - * Author: Anton Vorontsov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * I don't have specifications for the MCU firmware, I found this register - * and bits positions by the trial&error method. - */ -#define MCU_REG_CTRL 0x20 -#define MCU_CTRL_POFF 0x40 - -#define MCU_NUM_GPIO 2 - -struct mcu { - struct mutex lock; - struct device_node *np; - struct i2c_client *client; - struct of_gpio_chip of_gc; - u8 reg_ctrl; -}; - -static struct mcu *glob_mcu; - -static void mcu_power_off(void) -{ - struct mcu *mcu = glob_mcu; - - pr_info("Sending power-off request to the MCU...\n"); - mutex_lock(&mcu->lock); - i2c_smbus_write_byte_data(glob_mcu->client, MCU_REG_CTRL, - mcu->reg_ctrl | MCU_CTRL_POFF); - mutex_unlock(&mcu->lock); -} - -static void mcu_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) -{ - struct of_gpio_chip *of_gc = to_of_gpio_chip(gc); - struct mcu *mcu = container_of(of_gc, struct mcu, of_gc); - u8 bit = 1 << (4 + gpio); - - mutex_lock(&mcu->lock); - if (val) - mcu->reg_ctrl &= ~bit; - else - mcu->reg_ctrl |= bit; - - i2c_smbus_write_byte_data(mcu->client, MCU_REG_CTRL, mcu->reg_ctrl); - mutex_unlock(&mcu->lock); -} - -static int mcu_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) -{ - mcu_gpio_set(gc, gpio, val); - return 0; -} - -static int mcu_gpiochip_add(struct mcu *mcu) -{ - struct device_node *np; - struct of_gpio_chip *of_gc = &mcu->of_gc; - struct gpio_chip *gc = &of_gc->gc; - int ret; - - np = of_find_compatible_node(NULL, NULL, "fsl,mcu-mpc8349emitx"); - if (!np) - return -ENODEV; - - gc->owner = THIS_MODULE; - gc->label = np->full_name; - gc->can_sleep = 1; - gc->ngpio = MCU_NUM_GPIO; - gc->base = -1; - gc->set = mcu_gpio_set; - gc->direction_output = mcu_gpio_dir_out; - of_gc->gpio_cells = 2; - of_gc->xlate = of_gpio_simple_xlate; - - np->data = of_gc; - mcu->np = np; - - /* - * We don't want to lose the node, its ->data and ->full_name... - * So, if succeeded, we don't put the node here. - */ - ret = gpiochip_add(gc); - if (ret) - of_node_put(np); - return ret; -} - -static int mcu_gpiochip_remove(struct mcu *mcu) -{ - int ret; - - ret = gpiochip_remove(&mcu->of_gc.gc); - if (ret) - return ret; - of_node_put(mcu->np); - - return 0; -} - -static int __devinit mcu_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct mcu *mcu; - int ret; - - mcu = kzalloc(sizeof(*mcu), GFP_KERNEL); - if (!mcu) - return -ENOMEM; - - mutex_init(&mcu->lock); - mcu->client = client; - i2c_set_clientdata(client, mcu); - - ret = i2c_smbus_read_byte_data(mcu->client, MCU_REG_CTRL); - if (ret < 0) - goto err; - mcu->reg_ctrl = ret; - - ret = mcu_gpiochip_add(mcu); - if (ret) - goto err; - - /* XXX: this is potentially racy, but there is no lock for ppc_md */ - if (!ppc_md.power_off) { - glob_mcu = mcu; - ppc_md.power_off = mcu_power_off; - dev_info(&client->dev, "will provide power-off service\n"); - } - - return 0; -err: - kfree(mcu); - return ret; -} - -static int __devexit mcu_remove(struct i2c_client *client) -{ - struct mcu *mcu = i2c_get_clientdata(client); - int ret; - - if (glob_mcu == mcu) { - ppc_md.power_off = NULL; - glob_mcu = NULL; - } - - ret = mcu_gpiochip_remove(mcu); - if (ret) - return ret; - i2c_set_clientdata(client, NULL); - kfree(mcu); - return 0; -} - -static const struct i2c_device_id mcu_ids[] = { - { "mcu-mpc8349emitx", }, - {}, -}; -MODULE_DEVICE_TABLE(i2c, mcu_ids); - -static struct i2c_driver mcu_driver = { - .driver = { - .name = "mcu-mpc8349emitx", - .owner = THIS_MODULE, - }, - .probe = mcu_probe, - .remove = __devexit_p(mcu_remove), - .id_table = mcu_ids, -}; - -static int __init mcu_init(void) -{ - return i2c_add_driver(&mcu_driver); -} -module_init(mcu_init); - -static void __exit mcu_exit(void) -{ - i2c_del_driver(&mcu_driver); -} -module_exit(mcu_exit); - -MODULE_DESCRIPTION("Power Management and GPIO expander driver for " - "MPC8349E-mITX-compatible MCU"); -MODULE_AUTHOR("Anton Vorontsov "); -MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/chips/menelaus.c b/drivers/i2c/chips/menelaus.c deleted file mode 100644 index 4b364bae6b3..00000000000 --- a/drivers/i2c/chips/menelaus.c +++ /dev/null @@ -1,1285 +0,0 @@ -/* - * Copyright (C) 2004 Texas Instruments, Inc. - * - * Some parts based tps65010.c: - * Copyright (C) 2004 Texas Instruments and - * Copyright (C) 2004-2005 David Brownell - * - * Some parts based on tlv320aic24.c: - * Copyright (C) by Kai Svahn - * - * Changes for interrupt handling and clean-up by - * Tony Lindgren and Imre Deak - * Cleanup and generalized support for voltage setting by - * Juha Yrjola - * Added support for controlling VCORE and regulator sleep states, - * Amit Kucheria - * Copyright (C) 2005, 2006 Nokia Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#define DRIVER_NAME "menelaus" - -#define MENELAUS_I2C_ADDRESS 0x72 - -#define MENELAUS_REV 0x01 -#define MENELAUS_VCORE_CTRL1 0x02 -#define MENELAUS_VCORE_CTRL2 0x03 -#define MENELAUS_VCORE_CTRL3 0x04 -#define MENELAUS_VCORE_CTRL4 0x05 -#define MENELAUS_VCORE_CTRL5 0x06 -#define MENELAUS_DCDC_CTRL1 0x07 -#define MENELAUS_DCDC_CTRL2 0x08 -#define MENELAUS_DCDC_CTRL3 0x09 -#define MENELAUS_LDO_CTRL1 0x0A -#define MENELAUS_LDO_CTRL2 0x0B -#define MENELAUS_LDO_CTRL3 0x0C -#define MENELAUS_LDO_CTRL4 0x0D -#define MENELAUS_LDO_CTRL5 0x0E -#define MENELAUS_LDO_CTRL6 0x0F -#define MENELAUS_LDO_CTRL7 0x10 -#define MENELAUS_LDO_CTRL8 0x11 -#define MENELAUS_SLEEP_CTRL1 0x12 -#define MENELAUS_SLEEP_CTRL2 0x13 -#define MENELAUS_DEVICE_OFF 0x14 -#define MENELAUS_OSC_CTRL 0x15 -#define MENELAUS_DETECT_CTRL 0x16 -#define MENELAUS_INT_MASK1 0x17 -#define MENELAUS_INT_MASK2 0x18 -#define MENELAUS_INT_STATUS1 0x19 -#define MENELAUS_INT_STATUS2 0x1A -#define MENELAUS_INT_ACK1 0x1B -#define MENELAUS_INT_ACK2 0x1C -#define MENELAUS_GPIO_CTRL 0x1D -#define MENELAUS_GPIO_IN 0x1E -#define MENELAUS_GPIO_OUT 0x1F -#define MENELAUS_BBSMS 0x20 -#define MENELAUS_RTC_CTRL 0x21 -#define MENELAUS_RTC_UPDATE 0x22 -#define MENELAUS_RTC_SEC 0x23 -#define MENELAUS_RTC_MIN 0x24 -#define MENELAUS_RTC_HR 0x25 -#define MENELAUS_RTC_DAY 0x26 -#define MENELAUS_RTC_MON 0x27 -#define MENELAUS_RTC_YR 0x28 -#define MENELAUS_RTC_WKDAY 0x29 -#define MENELAUS_RTC_AL_SEC 0x2A -#define MENELAUS_RTC_AL_MIN 0x2B -#define MENELAUS_RTC_AL_HR 0x2C -#define MENELAUS_RTC_AL_DAY 0x2D -#define MENELAUS_RTC_AL_MON 0x2E -#define MENELAUS_RTC_AL_YR 0x2F -#define MENELAUS_RTC_COMP_MSB 0x30 -#define MENELAUS_RTC_COMP_LSB 0x31 -#define MENELAUS_S1_PULL_EN 0x32 -#define MENELAUS_S1_PULL_DIR 0x33 -#define MENELAUS_S2_PULL_EN 0x34 -#define MENELAUS_S2_PULL_DIR 0x35 -#define MENELAUS_MCT_CTRL1 0x36 -#define MENELAUS_MCT_CTRL2 0x37 -#define MENELAUS_MCT_CTRL3 0x38 -#define MENELAUS_MCT_PIN_ST 0x39 -#define MENELAUS_DEBOUNCE1 0x3A - -#define IH_MENELAUS_IRQS 12 -#define MENELAUS_MMC_S1CD_IRQ 0 /* MMC slot 1 card change */ -#define MENELAUS_MMC_S2CD_IRQ 1 /* MMC slot 2 card change */ -#define MENELAUS_MMC_S1D1_IRQ 2 /* MMC DAT1 low in slot 1 */ -#define MENELAUS_MMC_S2D1_IRQ 3 /* MMC DAT1 low in slot 2 */ -#define MENELAUS_LOWBAT_IRQ 4 /* Low battery */ -#define MENELAUS_HOTDIE_IRQ 5 /* Hot die detect */ -#define MENELAUS_UVLO_IRQ 6 /* UVLO detect */ -#define MENELAUS_TSHUT_IRQ 7 /* Thermal shutdown */ -#define MENELAUS_RTCTMR_IRQ 8 /* RTC timer */ -#define MENELAUS_RTCALM_IRQ 9 /* RTC alarm */ -#define MENELAUS_RTCERR_IRQ 10 /* RTC error */ -#define MENELAUS_PSHBTN_IRQ 11 /* Push button */ -#define MENELAUS_RESERVED12_IRQ 12 /* Reserved */ -#define MENELAUS_RESERVED13_IRQ 13 /* Reserved */ -#define MENELAUS_RESERVED14_IRQ 14 /* Reserved */ -#define MENELAUS_RESERVED15_IRQ 15 /* Reserved */ - -static void menelaus_work(struct work_struct *_menelaus); - -struct menelaus_chip { - struct mutex lock; - struct i2c_client *client; - struct work_struct work; -#ifdef CONFIG_RTC_DRV_TWL92330 - struct rtc_device *rtc; - u8 rtc_control; - unsigned uie:1; -#endif - unsigned vcore_hw_mode:1; - u8 mask1, mask2; - void (*handlers[16])(struct menelaus_chip *); - void (*mmc_callback)(void *data, u8 mask); - void *mmc_callback_data; -}; - -static struct menelaus_chip *the_menelaus; - -static int menelaus_write_reg(int reg, u8 value) -{ - int val = i2c_smbus_write_byte_data(the_menelaus->client, reg, value); - - if (val < 0) { - pr_err(DRIVER_NAME ": write error"); - return val; - } - - return 0; -} - -static int menelaus_read_reg(int reg) -{ - int val = i2c_smbus_read_byte_data(the_menelaus->client, reg); - - if (val < 0) - pr_err(DRIVER_NAME ": read error"); - - return val; -} - -static int menelaus_enable_irq(int irq) -{ - if (irq > 7) { - irq -= 8; - the_menelaus->mask2 &= ~(1 << irq); - return menelaus_write_reg(MENELAUS_INT_MASK2, - the_menelaus->mask2); - } else { - the_menelaus->mask1 &= ~(1 << irq); - return menelaus_write_reg(MENELAUS_INT_MASK1, - the_menelaus->mask1); - } -} - -static int menelaus_disable_irq(int irq) -{ - if (irq > 7) { - irq -= 8; - the_menelaus->mask2 |= (1 << irq); - return menelaus_write_reg(MENELAUS_INT_MASK2, - the_menelaus->mask2); - } else { - the_menelaus->mask1 |= (1 << irq); - return menelaus_write_reg(MENELAUS_INT_MASK1, - the_menelaus->mask1); - } -} - -static int menelaus_ack_irq(int irq) -{ - if (irq > 7) - return menelaus_write_reg(MENELAUS_INT_ACK2, 1 << (irq - 8)); - else - return menelaus_write_reg(MENELAUS_INT_ACK1, 1 << irq); -} - -/* Adds a handler for an interrupt. Does not run in interrupt context */ -static int menelaus_add_irq_work(int irq, - void (*handler)(struct menelaus_chip *)) -{ - int ret = 0; - - mutex_lock(&the_menelaus->lock); - the_menelaus->handlers[irq] = handler; - ret = menelaus_enable_irq(irq); - mutex_unlock(&the_menelaus->lock); - - return ret; -} - -/* Removes handler for an interrupt */ -static int menelaus_remove_irq_work(int irq) -{ - int ret = 0; - - mutex_lock(&the_menelaus->lock); - ret = menelaus_disable_irq(irq); - the_menelaus->handlers[irq] = NULL; - mutex_unlock(&the_menelaus->lock); - - return ret; -} - -/* - * Gets scheduled when a card detect interrupt happens. Note that in some cases - * this line is wired to card cover switch rather than the card detect switch - * in each slot. In this case the cards are not seen by menelaus. - * FIXME: Add handling for D1 too - */ -static void menelaus_mmc_cd_work(struct menelaus_chip *menelaus_hw) -{ - int reg; - unsigned char card_mask = 0; - - reg = menelaus_read_reg(MENELAUS_MCT_PIN_ST); - if (reg < 0) - return; - - if (!(reg & 0x1)) - card_mask |= (1 << 0); - - if (!(reg & 0x2)) - card_mask |= (1 << 1); - - if (menelaus_hw->mmc_callback) - menelaus_hw->mmc_callback(menelaus_hw->mmc_callback_data, - card_mask); -} - -/* - * Toggles the MMC slots between open-drain and push-pull mode. - */ -int menelaus_set_mmc_opendrain(int slot, int enable) -{ - int ret, val; - - if (slot != 1 && slot != 2) - return -EINVAL; - mutex_lock(&the_menelaus->lock); - ret = menelaus_read_reg(MENELAUS_MCT_CTRL1); - if (ret < 0) { - mutex_unlock(&the_menelaus->lock); - return ret; - } - val = ret; - if (slot == 1) { - if (enable) - val |= 1 << 2; - else - val &= ~(1 << 2); - } else { - if (enable) - val |= 1 << 3; - else - val &= ~(1 << 3); - } - ret = menelaus_write_reg(MENELAUS_MCT_CTRL1, val); - mutex_unlock(&the_menelaus->lock); - - return ret; -} -EXPORT_SYMBOL(menelaus_set_mmc_opendrain); - -int menelaus_set_slot_sel(int enable) -{ - int ret; - - mutex_lock(&the_menelaus->lock); - ret = menelaus_read_reg(MENELAUS_GPIO_CTRL); - if (ret < 0) - goto out; - ret |= 0x02; - if (enable) - ret |= 1 << 5; - else - ret &= ~(1 << 5); - ret = menelaus_write_reg(MENELAUS_GPIO_CTRL, ret); -out: - mutex_unlock(&the_menelaus->lock); - return ret; -} -EXPORT_SYMBOL(menelaus_set_slot_sel); - -int menelaus_set_mmc_slot(int slot, int enable, int power, int cd_en) -{ - int ret, val; - - if (slot != 1 && slot != 2) - return -EINVAL; - if (power >= 3) - return -EINVAL; - - mutex_lock(&the_menelaus->lock); - - ret = menelaus_read_reg(MENELAUS_MCT_CTRL2); - if (ret < 0) - goto out; - val = ret; - if (slot == 1) { - if (cd_en) - val |= (1 << 4) | (1 << 6); - else - val &= ~((1 << 4) | (1 << 6)); - } else { - if (cd_en) - val |= (1 << 5) | (1 << 7); - else - val &= ~((1 << 5) | (1 << 7)); - } - ret = menelaus_write_reg(MENELAUS_MCT_CTRL2, val); - if (ret < 0) - goto out; - - ret = menelaus_read_reg(MENELAUS_MCT_CTRL3); - if (ret < 0) - goto out; - val = ret; - if (slot == 1) { - if (enable) - val |= 1 << 0; - else - val &= ~(1 << 0); - } else { - int b; - - if (enable) - ret |= 1 << 1; - else - ret &= ~(1 << 1); - b = menelaus_read_reg(MENELAUS_MCT_CTRL2); - b &= ~0x03; - b |= power; - ret = menelaus_write_reg(MENELAUS_MCT_CTRL2, b); - if (ret < 0) - goto out; - } - /* Disable autonomous shutdown */ - val &= ~(0x03 << 2); - ret = menelaus_write_reg(MENELAUS_MCT_CTRL3, val); -out: - mutex_unlock(&the_menelaus->lock); - return ret; -} -EXPORT_SYMBOL(menelaus_set_mmc_slot); - -int menelaus_register_mmc_callback(void (*callback)(void *data, u8 card_mask), - void *data) -{ - int ret = 0; - - the_menelaus->mmc_callback_data = data; - the_menelaus->mmc_callback = callback; - ret = menelaus_add_irq_work(MENELAUS_MMC_S1CD_IRQ, - menelaus_mmc_cd_work); - if (ret < 0) - return ret; - ret = menelaus_add_irq_work(MENELAUS_MMC_S2CD_IRQ, - menelaus_mmc_cd_work); - if (ret < 0) - return ret; - ret = menelaus_add_irq_work(MENELAUS_MMC_S1D1_IRQ, - menelaus_mmc_cd_work); - if (ret < 0) - return ret; - ret = menelaus_add_irq_work(MENELAUS_MMC_S2D1_IRQ, - menelaus_mmc_cd_work); - - return ret; -} -EXPORT_SYMBOL(menelaus_register_mmc_callback); - -void menelaus_unregister_mmc_callback(void) -{ - menelaus_remove_irq_work(MENELAUS_MMC_S1CD_IRQ); - menelaus_remove_irq_work(MENELAUS_MMC_S2CD_IRQ); - menelaus_remove_irq_work(MENELAUS_MMC_S1D1_IRQ); - menelaus_remove_irq_work(MENELAUS_MMC_S2D1_IRQ); - - the_menelaus->mmc_callback = NULL; - the_menelaus->mmc_callback_data = 0; -} -EXPORT_SYMBOL(menelaus_unregister_mmc_callback); - -struct menelaus_vtg { - const char *name; - u8 vtg_reg; - u8 vtg_shift; - u8 vtg_bits; - u8 mode_reg; -}; - -struct menelaus_vtg_value { - u16 vtg; - u16 val; -}; - -static int menelaus_set_voltage(const struct menelaus_vtg *vtg, int mV, - int vtg_val, int mode) -{ - int val, ret; - struct i2c_client *c = the_menelaus->client; - - mutex_lock(&the_menelaus->lock); - if (vtg == 0) - goto set_voltage; - - ret = menelaus_read_reg(vtg->vtg_reg); - if (ret < 0) - goto out; - val = ret & ~(((1 << vtg->vtg_bits) - 1) << vtg->vtg_shift); - val |= vtg_val << vtg->vtg_shift; - - dev_dbg(&c->dev, "Setting voltage '%s'" - "to %d mV (reg 0x%02x, val 0x%02x)\n", - vtg->name, mV, vtg->vtg_reg, val); - - ret = menelaus_write_reg(vtg->vtg_reg, val); - if (ret < 0) - goto out; -set_voltage: - ret = menelaus_write_reg(vtg->mode_reg, mode); -out: - mutex_unlock(&the_menelaus->lock); - if (ret == 0) { - /* Wait for voltage to stabilize */ - msleep(1); - } - return ret; -} - -static int menelaus_get_vtg_value(int vtg, const struct menelaus_vtg_value *tbl, - int n) -{ - int i; - - for (i = 0; i < n; i++, tbl++) - if (tbl->vtg == vtg) - return tbl->val; - return -EINVAL; -} - -/* - * Vcore can be programmed in two ways: - * SW-controlled: Required voltage is programmed into VCORE_CTRL1 - * HW-controlled: Required range (roof-floor) is programmed into VCORE_CTRL3 - * and VCORE_CTRL4 - * - * Call correct 'set' function accordingly - */ - -static const struct menelaus_vtg_value vcore_values[] = { - { 1000, 0 }, - { 1025, 1 }, - { 1050, 2 }, - { 1075, 3 }, - { 1100, 4 }, - { 1125, 5 }, - { 1150, 6 }, - { 1175, 7 }, - { 1200, 8 }, - { 1225, 9 }, - { 1250, 10 }, - { 1275, 11 }, - { 1300, 12 }, - { 1325, 13 }, - { 1350, 14 }, - { 1375, 15 }, - { 1400, 16 }, - { 1425, 17 }, - { 1450, 18 }, -}; - -int menelaus_set_vcore_sw(unsigned int mV) -{ - int val, ret; - struct i2c_client *c = the_menelaus->client; - - val = menelaus_get_vtg_value(mV, vcore_values, - ARRAY_SIZE(vcore_values)); - if (val < 0) - return -EINVAL; - - dev_dbg(&c->dev, "Setting VCORE to %d mV (val 0x%02x)\n", mV, val); - - /* Set SW mode and the voltage in one go. */ - mutex_lock(&the_menelaus->lock); - ret = menelaus_write_reg(MENELAUS_VCORE_CTRL1, val); - if (ret == 0) - the_menelaus->vcore_hw_mode = 0; - mutex_unlock(&the_menelaus->lock); - msleep(1); - - return ret; -} - -int menelaus_set_vcore_hw(unsigned int roof_mV, unsigned int floor_mV) -{ - int fval, rval, val, ret; - struct i2c_client *c = the_menelaus->client; - - rval = menelaus_get_vtg_value(roof_mV, vcore_values, - ARRAY_SIZE(vcore_values)); - if (rval < 0) - return -EINVAL; - fval = menelaus_get_vtg_value(floor_mV, vcore_values, - ARRAY_SIZE(vcore_values)); - if (fval < 0) - return -EINVAL; - - dev_dbg(&c->dev, "Setting VCORE FLOOR to %d mV and ROOF to %d mV\n", - floor_mV, roof_mV); - - mutex_lock(&the_menelaus->lock); - ret = menelaus_write_reg(MENELAUS_VCORE_CTRL3, fval); - if (ret < 0) - goto out; - ret = menelaus_write_reg(MENELAUS_VCORE_CTRL4, rval); - if (ret < 0) - goto out; - if (!the_menelaus->vcore_hw_mode) { - val = menelaus_read_reg(MENELAUS_VCORE_CTRL1); - /* HW mode, turn OFF byte comparator */ - val |= ((1 << 7) | (1 << 5)); - ret = menelaus_write_reg(MENELAUS_VCORE_CTRL1, val); - the_menelaus->vcore_hw_mode = 1; - } - msleep(1); -out: - mutex_unlock(&the_menelaus->lock); - return ret; -} - -static const struct menelaus_vtg vmem_vtg = { - .name = "VMEM", - .vtg_reg = MENELAUS_LDO_CTRL1, - .vtg_shift = 0, - .vtg_bits = 2, - .mode_reg = MENELAUS_LDO_CTRL3, -}; - -static const struct menelaus_vtg_value vmem_values[] = { - { 1500, 0 }, - { 1800, 1 }, - { 1900, 2 }, - { 2500, 3 }, -}; - -int menelaus_set_vmem(unsigned int mV) -{ - int val; - - if (mV == 0) - return menelaus_set_voltage(&vmem_vtg, 0, 0, 0); - - val = menelaus_get_vtg_value(mV, vmem_values, ARRAY_SIZE(vmem_values)); - if (val < 0) - return -EINVAL; - return menelaus_set_voltage(&vmem_vtg, mV, val, 0x02); -} -EXPORT_SYMBOL(menelaus_set_vmem); - -static const struct menelaus_vtg vio_vtg = { - .name = "VIO", - .vtg_reg = MENELAUS_LDO_CTRL1, - .vtg_shift = 2, - .vtg_bits = 2, - .mode_reg = MENELAUS_LDO_CTRL4, -}; - -static const struct menelaus_vtg_value vio_values[] = { - { 1500, 0 }, - { 1800, 1 }, - { 2500, 2 }, - { 2800, 3 }, -}; - -int menelaus_set_vio(unsigned int mV) -{ - int val; - - if (mV == 0) - return menelaus_set_voltage(&vio_vtg, 0, 0, 0); - - val = menelaus_get_vtg_value(mV, vio_values, ARRAY_SIZE(vio_values)); - if (val < 0) - return -EINVAL; - return menelaus_set_voltage(&vio_vtg, mV, val, 0x02); -} -EXPORT_SYMBOL(menelaus_set_vio); - -static const struct menelaus_vtg_value vdcdc_values[] = { - { 1500, 0 }, - { 1800, 1 }, - { 2000, 2 }, - { 2200, 3 }, - { 2400, 4 }, - { 2800, 5 }, - { 3000, 6 }, - { 3300, 7 }, -}; - -static const struct menelaus_vtg vdcdc2_vtg = { - .name = "VDCDC2", - .vtg_reg = MENELAUS_DCDC_CTRL1, - .vtg_shift = 0, - .vtg_bits = 3, - .mode_reg = MENELAUS_DCDC_CTRL2, -}; - -static const struct menelaus_vtg vdcdc3_vtg = { - .name = "VDCDC3", - .vtg_reg = MENELAUS_DCDC_CTRL1, - .vtg_shift = 3, - .vtg_bits = 3, - .mode_reg = MENELAUS_DCDC_CTRL3, -}; - -int menelaus_set_vdcdc(int dcdc, unsigned int mV) -{ - const struct menelaus_vtg *vtg; - int val; - - if (dcdc != 2 && dcdc != 3) - return -EINVAL; - if (dcdc == 2) - vtg = &vdcdc2_vtg; - else - vtg = &vdcdc3_vtg; - - if (mV == 0) - return menelaus_set_voltage(vtg, 0, 0, 0); - - val = menelaus_get_vtg_value(mV, vdcdc_values, - ARRAY_SIZE(vdcdc_values)); - if (val < 0) - return -EINVAL; - return menelaus_set_voltage(vtg, mV, val, 0x03); -} - -static const struct menelaus_vtg_value vmmc_values[] = { - { 1850, 0 }, - { 2800, 1 }, - { 3000, 2 }, - { 3100, 3 }, -}; - -static const struct menelaus_vtg vmmc_vtg = { - .name = "VMMC", - .vtg_reg = MENELAUS_LDO_CTRL1, - .vtg_shift = 6, - .vtg_bits = 2, - .mode_reg = MENELAUS_LDO_CTRL7, -}; - -int menelaus_set_vmmc(unsigned int mV) -{ - int val; - - if (mV == 0) - return menelaus_set_voltage(&vmmc_vtg, 0, 0, 0); - - val = menelaus_get_vtg_value(mV, vmmc_values, ARRAY_SIZE(vmmc_values)); - if (val < 0) - return -EINVAL; - return menelaus_set_voltage(&vmmc_vtg, mV, val, 0x02); -} -EXPORT_SYMBOL(menelaus_set_vmmc); - - -static const struct menelaus_vtg_value vaux_values[] = { - { 1500, 0 }, - { 1800, 1 }, - { 2500, 2 }, - { 2800, 3 }, -}; - -static const struct menelaus_vtg vaux_vtg = { - .name = "VAUX", - .vtg_reg = MENELAUS_LDO_CTRL1, - .vtg_shift = 4, - .vtg_bits = 2, - .mode_reg = MENELAUS_LDO_CTRL6, -}; - -int menelaus_set_vaux(unsigned int mV) -{ - int val; - - if (mV == 0) - return menelaus_set_voltage(&vaux_vtg, 0, 0, 0); - - val = menelaus_get_vtg_value(mV, vaux_values, ARRAY_SIZE(vaux_values)); - if (val < 0) - return -EINVAL; - return menelaus_set_voltage(&vaux_vtg, mV, val, 0x02); -} -EXPORT_SYMBOL(menelaus_set_vaux); - -int menelaus_get_slot_pin_states(void) -{ - return menelaus_read_reg(MENELAUS_MCT_PIN_ST); -} -EXPORT_SYMBOL(menelaus_get_slot_pin_states); - -int menelaus_set_regulator_sleep(int enable, u32 val) -{ - int t, ret; - struct i2c_client *c = the_menelaus->client; - - mutex_lock(&the_menelaus->lock); - ret = menelaus_write_reg(MENELAUS_SLEEP_CTRL2, val); - if (ret < 0) - goto out; - - dev_dbg(&c->dev, "regulator sleep configuration: %02x\n", val); - - ret = menelaus_read_reg(MENELAUS_GPIO_CTRL); - if (ret < 0) - goto out; - t = ((1 << 6) | 0x04); - if (enable) - ret |= t; - else - ret &= ~t; - ret = menelaus_write_reg(MENELAUS_GPIO_CTRL, ret); -out: - mutex_unlock(&the_menelaus->lock); - return ret; -} - -/*-----------------------------------------------------------------------*/ - -/* Handles Menelaus interrupts. Does not run in interrupt context */ -static void menelaus_work(struct work_struct *_menelaus) -{ - struct menelaus_chip *menelaus = - container_of(_menelaus, struct menelaus_chip, work); - void (*handler)(struct menelaus_chip *menelaus); - - while (1) { - unsigned isr; - - isr = (menelaus_read_reg(MENELAUS_INT_STATUS2) - & ~menelaus->mask2) << 8; - isr |= menelaus_read_reg(MENELAUS_INT_STATUS1) - & ~menelaus->mask1; - if (!isr) - break; - - while (isr) { - int irq = fls(isr) - 1; - isr &= ~(1 << irq); - - mutex_lock(&menelaus->lock); - menelaus_disable_irq(irq); - menelaus_ack_irq(irq); - handler = menelaus->handlers[irq]; - if (handler) - handler(menelaus); - menelaus_enable_irq(irq); - mutex_unlock(&menelaus->lock); - } - } - enable_irq(menelaus->client->irq); -} - -/* - * We cannot use I2C in interrupt context, so we just schedule work. - */ -static irqreturn_t menelaus_irq(int irq, void *_menelaus) -{ - struct menelaus_chip *menelaus = _menelaus; - - disable_irq_nosync(irq); - (void)schedule_work(&menelaus->work); - - return IRQ_HANDLED; -} - -/*-----------------------------------------------------------------------*/ - -/* - * The RTC needs to be set once, then it runs on backup battery power. - * It supports alarms, including system wake alarms (from some modes); - * and 1/second IRQs if requested. - */ -#ifdef CONFIG_RTC_DRV_TWL92330 - -#define RTC_CTRL_RTC_EN (1 << 0) -#define RTC_CTRL_AL_EN (1 << 1) -#define RTC_CTRL_MODE12 (1 << 2) -#define RTC_CTRL_EVERY_MASK (3 << 3) -#define RTC_CTRL_EVERY_SEC (0 << 3) -#define RTC_CTRL_EVERY_MIN (1 << 3) -#define RTC_CTRL_EVERY_HR (2 << 3) -#define RTC_CTRL_EVERY_DAY (3 << 3) - -#define RTC_UPDATE_EVERY 0x08 - -#define RTC_HR_PM (1 << 7) - -static void menelaus_to_time(char *regs, struct rtc_time *t) -{ - t->tm_sec = bcd2bin(regs[0]); - t->tm_min = bcd2bin(regs[1]); - if (the_menelaus->rtc_control & RTC_CTRL_MODE12) { - t->tm_hour = bcd2bin(regs[2] & 0x1f) - 1; - if (regs[2] & RTC_HR_PM) - t->tm_hour += 12; - } else - t->tm_hour = bcd2bin(regs[2] & 0x3f); - t->tm_mday = bcd2bin(regs[3]); - t->tm_mon = bcd2bin(regs[4]) - 1; - t->tm_year = bcd2bin(regs[5]) + 100; -} - -static int time_to_menelaus(struct rtc_time *t, int regnum) -{ - int hour, status; - - status = menelaus_write_reg(regnum++, bin2bcd(t->tm_sec)); - if (status < 0) - goto fail; - - status = menelaus_write_reg(regnum++, bin2bcd(t->tm_min)); - if (status < 0) - goto fail; - - if (the_menelaus->rtc_control & RTC_CTRL_MODE12) { - hour = t->tm_hour + 1; - if (hour > 12) - hour = RTC_HR_PM | bin2bcd(hour - 12); - else - hour = bin2bcd(hour); - } else - hour = bin2bcd(t->tm_hour); - status = menelaus_write_reg(regnum++, hour); - if (status < 0) - goto fail; - - status = menelaus_write_reg(regnum++, bin2bcd(t->tm_mday)); - if (status < 0) - goto fail; - - status = menelaus_write_reg(regnum++, bin2bcd(t->tm_mon + 1)); - if (status < 0) - goto fail; - - status = menelaus_write_reg(regnum++, bin2bcd(t->tm_year - 100)); - if (status < 0) - goto fail; - - return 0; -fail: - dev_err(&the_menelaus->client->dev, "rtc write reg %02x, err %d\n", - --regnum, status); - return status; -} - -static int menelaus_read_time(struct device *dev, struct rtc_time *t) -{ - struct i2c_msg msg[2]; - char regs[7]; - int status; - - /* block read date and time registers */ - regs[0] = MENELAUS_RTC_SEC; - - msg[0].addr = MENELAUS_I2C_ADDRESS; - msg[0].flags = 0; - msg[0].len = 1; - msg[0].buf = regs; - - msg[1].addr = MENELAUS_I2C_ADDRESS; - msg[1].flags = I2C_M_RD; - msg[1].len = sizeof(regs); - msg[1].buf = regs; - - status = i2c_transfer(the_menelaus->client->adapter, msg, 2); - if (status != 2) { - dev_err(dev, "%s error %d\n", "read", status); - return -EIO; - } - - menelaus_to_time(regs, t); - t->tm_wday = bcd2bin(regs[6]); - - return 0; -} - -static int menelaus_set_time(struct device *dev, struct rtc_time *t) -{ - int status; - - /* write date and time registers */ - status = time_to_menelaus(t, MENELAUS_RTC_SEC); - if (status < 0) - return status; - status = menelaus_write_reg(MENELAUS_RTC_WKDAY, bin2bcd(t->tm_wday)); - if (status < 0) { - dev_err(&the_menelaus->client->dev, "rtc write reg %02x " - "err %d\n", MENELAUS_RTC_WKDAY, status); - return status; - } - - /* now commit the write */ - status = menelaus_write_reg(MENELAUS_RTC_UPDATE, RTC_UPDATE_EVERY); - if (status < 0) - dev_err(&the_menelaus->client->dev, "rtc commit time, err %d\n", - status); - - return 0; -} - -static int menelaus_read_alarm(struct device *dev, struct rtc_wkalrm *w) -{ - struct i2c_msg msg[2]; - char regs[6]; - int status; - - /* block read alarm registers */ - regs[0] = MENELAUS_RTC_AL_SEC; - - msg[0].addr = MENELAUS_I2C_ADDRESS; - msg[0].flags = 0; - msg[0].len = 1; - msg[0].buf = regs; - - msg[1].addr = MENELAUS_I2C_ADDRESS; - msg[1].flags = I2C_M_RD; - msg[1].len = sizeof(regs); - msg[1].buf = regs; - - status = i2c_transfer(the_menelaus->client->adapter, msg, 2); - if (status != 2) { - dev_err(dev, "%s error %d\n", "alarm read", status); - return -EIO; - } - - menelaus_to_time(regs, &w->time); - - w->enabled = !!(the_menelaus->rtc_control & RTC_CTRL_AL_EN); - - /* NOTE we *could* check if actually pending... */ - w->pending = 0; - - return 0; -} - -static int menelaus_set_alarm(struct device *dev, struct rtc_wkalrm *w) -{ - int status; - - if (the_menelaus->client->irq <= 0 && w->enabled) - return -ENODEV; - - /* clear previous alarm enable */ - if (the_menelaus->rtc_control & RTC_CTRL_AL_EN) { - the_menelaus->rtc_control &= ~RTC_CTRL_AL_EN; - status = menelaus_write_reg(MENELAUS_RTC_CTRL, - the_menelaus->rtc_control); - if (status < 0) - return status; - } - - /* write alarm registers */ - status = time_to_menelaus(&w->time, MENELAUS_RTC_AL_SEC); - if (status < 0) - return status; - - /* enable alarm if requested */ - if (w->enabled) { - the_menelaus->rtc_control |= RTC_CTRL_AL_EN; - status = menelaus_write_reg(MENELAUS_RTC_CTRL, - the_menelaus->rtc_control); - } - - return status; -} - -#ifdef CONFIG_RTC_INTF_DEV - -static void menelaus_rtc_update_work(struct menelaus_chip *m) -{ - /* report 1/sec update */ - local_irq_disable(); - rtc_update_irq(m->rtc, 1, RTC_IRQF | RTC_UF); - local_irq_enable(); -} - -static int menelaus_ioctl(struct device *dev, unsigned cmd, unsigned long arg) -{ - int status; - - if (the_menelaus->client->irq <= 0) - return -ENOIOCTLCMD; - - switch (cmd) { - /* alarm IRQ */ - case RTC_AIE_ON: - if (the_menelaus->rtc_control & RTC_CTRL_AL_EN) - return 0; - the_menelaus->rtc_control |= RTC_CTRL_AL_EN; - break; - case RTC_AIE_OFF: - if (!(the_menelaus->rtc_control & RTC_CTRL_AL_EN)) - return 0; - the_menelaus->rtc_control &= ~RTC_CTRL_AL_EN; - break; - /* 1/second "update" IRQ */ - case RTC_UIE_ON: - if (the_menelaus->uie) - return 0; - status = menelaus_remove_irq_work(MENELAUS_RTCTMR_IRQ); - status = menelaus_add_irq_work(MENELAUS_RTCTMR_IRQ, - menelaus_rtc_update_work); - if (status == 0) - the_menelaus->uie = 1; - return status; - case RTC_UIE_OFF: - if (!the_menelaus->uie) - return 0; - status = menelaus_remove_irq_work(MENELAUS_RTCTMR_IRQ); - if (status == 0) - the_menelaus->uie = 0; - return status; - default: - return -ENOIOCTLCMD; - } - return menelaus_write_reg(MENELAUS_RTC_CTRL, the_menelaus->rtc_control); -} - -#else -#define menelaus_ioctl NULL -#endif - -/* REVISIT no compensation register support ... */ - -static const struct rtc_class_ops menelaus_rtc_ops = { - .ioctl = menelaus_ioctl, - .read_time = menelaus_read_time, - .set_time = menelaus_set_time, - .read_alarm = menelaus_read_alarm, - .set_alarm = menelaus_set_alarm, -}; - -static void menelaus_rtc_alarm_work(struct menelaus_chip *m) -{ - /* report alarm */ - local_irq_disable(); - rtc_update_irq(m->rtc, 1, RTC_IRQF | RTC_AF); - local_irq_enable(); - - /* then disable it; alarms are oneshot */ - the_menelaus->rtc_control &= ~RTC_CTRL_AL_EN; - menelaus_write_reg(MENELAUS_RTC_CTRL, the_menelaus->rtc_control); -} - -static inline void menelaus_rtc_init(struct menelaus_chip *m) -{ - int alarm = (m->client->irq > 0); - - /* assume 32KDETEN pin is pulled high */ - if (!(menelaus_read_reg(MENELAUS_OSC_CTRL) & 0x80)) { - dev_dbg(&m->client->dev, "no 32k oscillator\n"); - return; - } - - /* support RTC alarm; it can issue wakeups */ - if (alarm) { - if (menelaus_add_irq_work(MENELAUS_RTCALM_IRQ, - menelaus_rtc_alarm_work) < 0) { - dev_err(&m->client->dev, "can't handle RTC alarm\n"); - return; - } - device_init_wakeup(&m->client->dev, 1); - } - - /* be sure RTC is enabled; allow 1/sec irqs; leave 12hr mode alone */ - m->rtc_control = menelaus_read_reg(MENELAUS_RTC_CTRL); - if (!(m->rtc_control & RTC_CTRL_RTC_EN) - || (m->rtc_control & RTC_CTRL_AL_EN) - || (m->rtc_control & RTC_CTRL_EVERY_MASK)) { - if (!(m->rtc_control & RTC_CTRL_RTC_EN)) { - dev_warn(&m->client->dev, "rtc clock needs setting\n"); - m->rtc_control |= RTC_CTRL_RTC_EN; - } - m->rtc_control &= ~RTC_CTRL_EVERY_MASK; - m->rtc_control &= ~RTC_CTRL_AL_EN; - menelaus_write_reg(MENELAUS_RTC_CTRL, m->rtc_control); - } - - m->rtc = rtc_device_register(DRIVER_NAME, - &m->client->dev, - &menelaus_rtc_ops, THIS_MODULE); - if (IS_ERR(m->rtc)) { - if (alarm) { - menelaus_remove_irq_work(MENELAUS_RTCALM_IRQ); - device_init_wakeup(&m->client->dev, 0); - } - dev_err(&m->client->dev, "can't register RTC: %d\n", - (int) PTR_ERR(m->rtc)); - the_menelaus->rtc = NULL; - } -} - -#else - -static inline void menelaus_rtc_init(struct menelaus_chip *m) -{ - /* nothing */ -} - -#endif - -/*-----------------------------------------------------------------------*/ - -static struct i2c_driver menelaus_i2c_driver; - -static int menelaus_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct menelaus_chip *menelaus; - int rev = 0, val; - int err = 0; - struct menelaus_platform_data *menelaus_pdata = - client->dev.platform_data; - - if (the_menelaus) { - dev_dbg(&client->dev, "only one %s for now\n", - DRIVER_NAME); - return -ENODEV; - } - - menelaus = kzalloc(sizeof *menelaus, GFP_KERNEL); - if (!menelaus) - return -ENOMEM; - - i2c_set_clientdata(client, menelaus); - - the_menelaus = menelaus; - menelaus->client = client; - - /* If a true probe check the device */ - rev = menelaus_read_reg(MENELAUS_REV); - if (rev < 0) { - pr_err(DRIVER_NAME ": device not found"); - err = -ENODEV; - goto fail1; - } - - /* Ack and disable all Menelaus interrupts */ - menelaus_write_reg(MENELAUS_INT_ACK1, 0xff); - menelaus_write_reg(MENELAUS_INT_ACK2, 0xff); - menelaus_write_reg(MENELAUS_INT_MASK1, 0xff); - menelaus_write_reg(MENELAUS_INT_MASK2, 0xff); - menelaus->mask1 = 0xff; - menelaus->mask2 = 0xff; - - /* Set output buffer strengths */ - menelaus_write_reg(MENELAUS_MCT_CTRL1, 0x73); - - if (client->irq > 0) { - err = request_irq(client->irq, menelaus_irq, IRQF_DISABLED, - DRIVER_NAME, menelaus); - if (err) { - dev_dbg(&client->dev, "can't get IRQ %d, err %d\n", - client->irq, err); - goto fail1; - } - } - - mutex_init(&menelaus->lock); - INIT_WORK(&menelaus->work, menelaus_work); - - pr_info("Menelaus rev %d.%d\n", rev >> 4, rev & 0x0f); - - val = menelaus_read_reg(MENELAUS_VCORE_CTRL1); - if (val < 0) - goto fail2; - if (val & (1 << 7)) - menelaus->vcore_hw_mode = 1; - else - menelaus->vcore_hw_mode = 0; - - if (menelaus_pdata != NULL && menelaus_pdata->late_init != NULL) { - err = menelaus_pdata->late_init(&client->dev); - if (err < 0) - goto fail2; - } - - menelaus_rtc_init(menelaus); - - return 0; -fail2: - free_irq(client->irq, menelaus); - flush_scheduled_work(); -fail1: - kfree(menelaus); - return err; -} - -static int __exit menelaus_remove(struct i2c_client *client) -{ - struct menelaus_chip *menelaus = i2c_get_clientdata(client); - - free_irq(client->irq, menelaus); - kfree(menelaus); - i2c_set_clientdata(client, NULL); - the_menelaus = NULL; - return 0; -} - -static const struct i2c_device_id menelaus_id[] = { - { "menelaus", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, menelaus_id); - -static struct i2c_driver menelaus_i2c_driver = { - .driver = { - .name = DRIVER_NAME, - }, - .probe = menelaus_probe, - .remove = __exit_p(menelaus_remove), - .id_table = menelaus_id, -}; - -static int __init menelaus_init(void) -{ - int res; - - res = i2c_add_driver(&menelaus_i2c_driver); - if (res < 0) { - pr_err(DRIVER_NAME ": driver registration failed\n"); - return res; - } - - return 0; -} - -static void __exit menelaus_exit(void) -{ - i2c_del_driver(&menelaus_i2c_driver); - - /* FIXME: Shutdown menelaus parts that can be shut down */ -} - -MODULE_AUTHOR("Texas Instruments, Inc. (and others)"); -MODULE_DESCRIPTION("I2C interface for Menelaus."); -MODULE_LICENSE("GPL"); - -module_init(menelaus_init); -module_exit(menelaus_exit); diff --git a/drivers/i2c/chips/pcf50633.h b/drivers/i2c/chips/pcf50633.h new file mode 100644 index 00000000000..5d54131db5a --- /dev/null +++ b/drivers/i2c/chips/pcf50633.h @@ -0,0 +1,349 @@ +#ifndef _PCF50633_H +#define _PCF50633_H + +/* Philips PCF50633 Power Managemnt Unit (PMU) driver + * (C) 2006-2007 by Openmoko, Inc. + * Author: Harald Welte + * + */ + +enum pfc50633_regs { + PCF50633_REG_VERSION = 0x00, + PCF50633_REG_VARIANT = 0x01, + PCF50633_REG_INT1 = 0x02, /* Interrupt Status */ + PCF50633_REG_INT2 = 0x03, /* Interrupt Status */ + PCF50633_REG_INT3 = 0x04, /* Interrupt Status */ + PCF50633_REG_INT4 = 0x05, /* Interrupt Status */ + PCF50633_REG_INT5 = 0x06, /* Interrupt Status */ + PCF50633_REG_INT1M = 0x07, /* Interrupt Mask */ + PCF50633_REG_INT2M = 0x08, /* Interrupt Mask */ + PCF50633_REG_INT3M = 0x09, /* Interrupt Mask */ + PCF50633_REG_INT4M = 0x0a, /* Interrupt Mask */ + PCF50633_REG_INT5M = 0x0b, /* Interrupt Mask */ + PCF50633_REG_OOCSHDWN = 0x0c, + PCF50633_REG_OOCWAKE = 0x0d, + PCF50633_REG_OOCTIM1 = 0x0e, + PCF50633_REG_OOCTIM2 = 0x0f, + PCF50633_REG_OOCMODE = 0x10, + PCF50633_REG_OOCCTL = 0x11, + PCF50633_REG_OOCSTAT = 0x12, + PCF50633_REG_GPIOCTL = 0x13, + PCF50633_REG_GPIO1CFG = 0x14, + PCF50633_REG_GPIO2CFG = 0x15, + PCF50633_REG_GPIO3CFG = 0x16, + PCF50633_REG_GPOCFG = 0x17, + PCF50633_REG_BVMCTL = 0x18, + PCF50633_REG_SVMCTL = 0x19, + PCF50633_REG_AUTOOUT = 0x1a, + PCF50633_REG_AUTOENA = 0x1b, + PCF50633_REG_AUTOCTL = 0x1c, + PCF50633_REG_AUTOMXC = 0x1d, + PCF50633_REG_DOWN1OUT = 0x1e, + PCF50633_REG_DOWN1ENA = 0x1f, + PCF50633_REG_DOWN1CTL = 0x20, + PCF50633_REG_DOWN1MXC = 0x21, + PCF50633_REG_DOWN2OUT = 0x22, + PCF50633_REG_DOWN2ENA = 0x23, + PCF50633_REG_DOWN2CTL = 0x24, + PCF50633_REG_DOWN2MXC = 0x25, + PCF50633_REG_MEMLDOOUT = 0x26, + PCF50633_REG_MEMLDOENA = 0x27, + PCF50633_REG_LEDOUT = 0x28, + PCF50633_REG_LEDENA = 0x29, + PCF50633_REG_LEDCTL = 0x2a, + PCF50633_REG_LEDDIM = 0x2b, + /* reserved */ + PCF50633_REG_LDO1OUT = 0x2d, + PCF50633_REG_LDO1ENA = 0x2e, + PCF50633_REG_LDO2OUT = 0x2f, + PCF50633_REG_LDO2ENA = 0x30, + PCF50633_REG_LDO3OUT = 0x31, + PCF50633_REG_LDO3ENA = 0x32, + PCF50633_REG_LDO4OUT = 0x33, + PCF50633_REG_LDO4ENA = 0x34, + PCF50633_REG_LDO5OUT = 0x35, + PCF50633_REG_LDO5ENA = 0x36, + PCF50633_REG_LDO6OUT = 0x37, + PCF50633_REG_LDO6ENA = 0x38, + PCF50633_REG_HCLDOOUT = 0x39, + PCF50633_REG_HCLDOENA = 0x3a, + PCF50633_REG_STBYCTL1 = 0x3b, + PCF50633_REG_STBYCTL2 = 0x3c, + PCF50633_REG_DEBPF1 = 0x3d, + PCF50633_REG_DEBPF2 = 0x3e, + PCF50633_REG_DEBPF3 = 0x3f, + PCF50633_REG_HCLDOOVL = 0x40, + PCF50633_REG_DCDCSTAT = 0x41, + PCF50633_REG_LDOSTAT = 0x42, + PCF50633_REG_MBCC1 = 0x43, + PCF50633_REG_MBCC2 = 0x44, + PCF50633_REG_MBCC3 = 0x45, + PCF50633_REG_MBCC4 = 0x46, + PCF50633_REG_MBCC5 = 0x47, + PCF50633_REG_MBCC6 = 0x48, + PCF50633_REG_MBCC7 = 0x49, + PCF50633_REG_MBCC8 = 0x4a, + PCF50633_REG_MBCS1 = 0x4b, + PCF50633_REG_MBCS2 = 0x4c, + PCF50633_REG_MBCS3 = 0x4d, + PCF50633_REG_BBCCTL = 0x4e, + PCF50633_REG_ALMGAIN = 0x4f, + PCF50633_REG_ALMDATA = 0x50, + /* reserved */ + PCF50633_REG_ADCC3 = 0x52, + PCF50633_REG_ADCC2 = 0x53, + PCF50633_REG_ADCC1 = 0x54, + PCF50633_REG_ADCS1 = 0x55, + PCF50633_REG_ADCS2 = 0x56, + PCF50633_REG_ADCS3 = 0x57, + /* reserved */ + PCF50633_REG_RTCSC = 0x59, /* Second */ + PCF50633_REG_RTCMN = 0x5a, /* Minute */ + PCF50633_REG_RTCHR = 0x5b, /* Hour */ + PCF50633_REG_RTCWD = 0x5c, /* Weekday */ + PCF50633_REG_RTCDT = 0x5d, /* Day */ + PCF50633_REG_RTCMT = 0x5e, /* Month */ + PCF50633_REG_RTCYR = 0x5f, /* Year */ + PCF50633_REG_RTCSCA = 0x60, /* Alarm Second */ + PCF50633_REG_RTCMNA = 0x61, /* Alarm Minute */ + PCF50633_REG_RTCHRA = 0x62, /* Alarm Hour */ + PCF50633_REG_RTCWDA = 0x63, /* Alarm Weekday */ + PCF50633_REG_RTCDTA = 0x64, /* Alarm Day */ + PCF50633_REG_RTCMTA = 0x65, /* Alarm Month */ + PCF50633_REG_RTCYRA = 0x66, /* Alarm Year */ + + PCF50633_REG_MEMBYTE0 = 0x67, + PCF50633_REG_MEMBYTE1 = 0x68, + PCF50633_REG_MEMBYTE2 = 0x69, + PCF50633_REG_MEMBYTE3 = 0x6a, + PCF50633_REG_MEMBYTE4 = 0x6b, + PCF50633_REG_MEMBYTE5 = 0x6c, + PCF50633_REG_MEMBYTE6 = 0x6d, + PCF50633_REG_MEMBYTE7 = 0x6e, + /* reserved */ + PCF50633_REG_DCDCPFM = 0x84, + __NUM_PCF50633_REGS +}; + + +enum pcf50633_reg_oocshdwn { + PCF50633_OOCSHDWN_GOSTDBY = 0x01, + PCF50633_OOCSHDWN_TOTRST = 0x04, + PCF50633_OOCSHDWN_COLDBOOT = 0x08, +}; + +enum pcf50633_reg_oocwake { + PCF50633_OOCWAKE_ONKEY = 0x01, + PCF50633_OOCWAKE_EXTON1 = 0x02, + PCF50633_OOCWAKE_EXTON2 = 0x04, + PCF50633_OOCWAKE_EXTON3 = 0x08, + PCF50633_OOCWAKE_RTC = 0x10, + /* reserved */ + PCF50633_OOCWAKE_USB = 0x40, + PCF50633_OOCWAKE_ADP = 0x80, +}; + +enum pcf50633_reg_mbcc1 { + PCF50633_MBCC1_CHGENA = 0x01, /* Charger enable */ + PCF50633_MBCC1_AUTOSTOP = 0x02, + PCF50633_MBCC1_AUTORES = 0x04, /* automatic resume */ + PCF50633_MBCC1_RESUME = 0x08, /* explicit resume cmd */ + PCF50633_MBCC1_RESTART = 0x10, /* restart charging */ + PCF50633_MBCC1_PREWDTIME_60M = 0x20, /* max. precharging time */ + PCF50633_MBCC1_WDTIME_1H = 0x00, + PCF50633_MBCC1_WDTIME_2H = 0x40, + PCF50633_MBCC1_WDTIME_4H = 0x80, + PCF50633_MBCC1_WDTIME_6H = 0xc0, +}; +#define PCF50633_MBCC1_WDTIME_MASK 0xc0 + +enum pcf50633_reg_mbcc2 { + PCF50633_MBCC2_VBATCOND_2V7 = 0x00, + PCF50633_MBCC2_VBATCOND_2V85 = 0x01, + PCF50633_MBCC2_VBATCOND_3V0 = 0x02, + PCF50633_MBCC2_VBATCOND_3V15 = 0x03, + PCF50633_MBCC2_VMAX_4V = 0x00, + PCF50633_MBCC2_VMAX_4V20 = 0x28, + PCF50633_MBCC2_VRESDEBTIME_64S = 0x80, /* debounce time (32/64sec) */ +}; +#define PCF50633_MBCC2_VBATCOND_MASK 0x03 +#define PCF50633_MBCC2_VMAX_MASK 0x3c + +enum pcf50633_reg_adcc1 { + PCF50633_ADCC1_ADCSTART = 0x01, + PCF50633_ADCC1_RES_10BIT = 0x02, + PCF50633_ADCC1_AVERAGE_NO = 0x00, + PCF50633_ADCC1_AVERAGE_4 = 0x04, + PCF50633_ADCC1_AVERAGE_8 = 0x08, + PCF50633_ADCC1_AVERAGE_16 = 0x0c, + + PCF50633_ADCC1_MUX_BATSNS_RES = 0x00, + PCF50633_ADCC1_MUX_BATSNS_SUBTR = 0x10, + PCF50633_ADCC1_MUX_ADCIN2_RES = 0x20, + PCF50633_ADCC1_MUX_ADCIN2_SUBTR = 0x30, + PCF50633_ADCC1_MUX_BATTEMP = 0x60, + PCF50633_ADCC1_MUX_ADCIN1 = 0x70, +}; +#define PCF50633_ADCC1_AVERAGE_MASK 0x0c +#define PCF50633_ADCC1_ADCMUX_MASK 0xf0 + +enum pcf50633_reg_adcc2 { + PCF50633_ADCC2_RATIO_NONE = 0x00, + PCF50633_ADCC2_RATIO_BATTEMP = 0x01, + PCF50633_ADCC2_RATIO_ADCIN1 = 0x02, + PCF50633_ADCC2_RATIO_BOTH = 0x03, + PCF50633_ADCC2_RATIOSETTL_100US = 0x04, +}; +#define PCF50633_ADCC2_RATIO_MASK 0x03 + +enum pcf50633_reg_adcc3 { + PCF50633_ADCC3_ACCSW_EN = 0x01, + PCF50633_ADCC3_NTCSW_EN = 0x04, + PCF50633_ADCC3_RES_DIV_TWO = 0x10, + PCF50633_ADCC3_RES_DIV_THREE = 0x00, +}; + +enum pcf50633_reg_adcs3 { + PCF50633_ADCS3_REF_NTCSW = 0x00, + PCF50633_ADCS3_REF_ACCSW = 0x10, + PCF50633_ADCS3_REF_2V0 = 0x20, + PCF50633_ADCS3_REF_VISA = 0x30, + PCF50633_ADCS3_REF_2V0_2 = 0x70, + PCF50633_ADCS3_ADCRDY = 0x80, +}; +#define PCF50633_ADCS3_ADCDAT1L_MASK 0x03 +#define PCF50633_ADCS3_ADCDAT2L_MASK 0x0c +#define PCF50633_ADCS3_ADCDAT2L_SHIFT 2 +#define PCF50633_ASCS3_REF_MASK 0x70 + +enum pcf50633_regulator_enable { + PCF50633_REGULATOR_ON = 0x01, + PCF50633_REGULATOR_ON_GPIO1 = 0x02, + PCF50633_REGULATOR_ON_GPIO2 = 0x04, + PCF50633_REGULATOR_ON_GPIO3 = 0x08, +}; +#define PCF50633_REGULATOR_ON_MASK 0x0f + +enum pcf50633_regulator_phase { + PCF50633_REGULATOR_ACTPH1 = 0x00, + PCF50633_REGULATOR_ACTPH2 = 0x10, + PCF50633_REGULATOR_ACTPH3 = 0x20, + PCF50633_REGULATOR_ACTPH4 = 0x30, +}; +#define PCF50633_REGULATOR_ACTPH_MASK 0x30 + +enum pcf50633_reg_gpocfg { + PCF50633_GPOCFG_GPOSEL_0 = 0x00, + PCF50633_GPOCFG_GPOSEL_LED_NFET = 0x01, + PCF50633_GPOCFG_GPOSEL_SYSxOK = 0x02, + PCF50633_GPOCFG_GPOSEL_CLK32K = 0x03, + PCF50633_GPOCFG_GPOSEL_ADAPUSB = 0x04, + PCF50633_GPOCFG_GPOSEL_USBxOK = 0x05, + PCF50633_GPOCFG_GPOSEL_ACTPH4 = 0x06, + PCF50633_GPOCFG_GPOSEL_1 = 0x07, + PCF50633_GPOCFG_GPOSEL_INVERSE = 0x08, +}; +#define PCF50633_GPOCFG_GPOSEL_MASK 0x07 + +#if 0 +enum pcf50633_reg_mbcc1 { + PCF50633_MBCC1_CHGENA = 0x01, + PCF50633_MBCC1_AUTOSTOP = 0x02, + PCF50633_MBCC1_AUTORES = 0x04, + PCF50633_MBCC1_RESUME = 0x08, + PCF50633_MBCC1_RESTART = 0x10, + PCF50633_MBCC1_PREWDTIME_30MIN = 0x00, + PCF50633_MBCC1_PREWDTIME_60MIN = 0x20, + PCF50633_MBCC1_WDTIME_2HRS = 0x40, + PCF50633_MBCC1_WDTIME_4HRS = 0x80, + PCF50633_MBCC1_WDTIME_6HRS = 0xc0, +}; + +enum pcf50633_reg_mbcc2 { + PCF50633_MBCC2_VBATCOND_2V7 = 0x00, + PCF50633_MBCC2_VBATCOND_2V85 = 0x01, + PCF50633_MBCC2_VBATCOND_3V0 = 0x02, + PCF50633_MBCC2_VBATCOND_3V15 = 0x03, + PCF50633_MBCC2_VRESDEBTIME_64S = 0x80, +}; +#define PCF50633_MBCC2_VMAX_MASK 0x3c +#endif + +enum pcf50633_reg_mbcc7 { + PCF50633_MBCC7_USB_100mA = 0x00, + PCF50633_MBCC7_USB_500mA = 0x01, + PCF50633_MBCC7_USB_1000mA = 0x02, + PCF50633_MBCC7_USB_SUSPEND = 0x03, + PCF50633_MBCC7_BATTEMP_EN = 0x04, + PCF50633_MBCC7_BATSYSIMAX_1A6 = 0x00, + PCF50633_MBCC7_BATSYSIMAX_1A8 = 0x40, + PCF50633_MBCC7_BATSYSIMAX_2A0 = 0x80, + PCF50633_MBCC7_BATSYSIMAX_2A2 = 0xc0, +}; +#define PCF56033_MBCC7_USB_MASK 0x03 + +enum pcf50633_reg_mbcc8 { + PCF50633_MBCC8_USBENASUS = 0x10, +}; + +enum pcf50633_reg_mbcs1 { + PCF50633_MBCS1_USBPRES = 0x01, + PCF50633_MBCS1_USBOK = 0x02, + PCF50633_MBCS1_ADAPTPRES = 0x04, + PCF50633_MBCS1_ADAPTOK = 0x08, + PCF50633_MBCS1_TBAT_OK = 0x00, + PCF50633_MBCS1_TBAT_ABOVE = 0x10, + PCF50633_MBCS1_TBAT_BELOW = 0x20, + PCF50633_MBCS1_TBAT_UNDEF = 0x30, + PCF50633_MBCS1_PREWDTEXP = 0x40, + PCF50633_MBCS1_WDTEXP = 0x80, +}; + +enum pcf50633_reg_mbcs2_mbcmod { + PCF50633_MBCS2_MBC_PLAY = 0x00, + PCF50633_MBCS2_MBC_USB_PRE = 0x01, + PCF50633_MBCS2_MBC_USB_PRE_WAIT = 0x02, + PCF50633_MBCS2_MBC_USB_FAST = 0x03, + PCF50633_MBCS2_MBC_USB_FAST_WAIT= 0x04, + PCF50633_MBCS2_MBC_USB_SUSPEND = 0x05, + PCF50633_MBCS2_MBC_ADP_PRE = 0x06, + PCF50633_MBCS2_MBC_ADP_PRE_WAIT = 0x07, + PCF50633_MBCS2_MBC_ADP_FAST = 0x08, + PCF50633_MBCS2_MBC_ADP_FAST_WAIT= 0x09, + PCF50633_MBCS2_MBC_BAT_FULL = 0x0a, + PCF50633_MBCS2_MBC_HALT = 0x0b, +}; +#define PCF50633_MBCS2_MBC_MASK 0x0f +enum pcf50633_reg_mbcs2_chgstat { + PCF50633_MBCS2_CHGS_NONE = 0x00, + PCF50633_MBCS2_CHGS_ADAPTER = 0x10, + PCF50633_MBCS2_CHGS_USB = 0x20, + PCF50633_MBCS2_CHGS_BOTH = 0x30, +}; +#define PCF50633_MBCS2_RESSTAT_AUTO 0x40 + +enum pcf50633_reg_mbcs3 { + PCF50633_MBCS3_USBLIM_PLAY = 0x01, + PCF50633_MBCS3_USBLIM_CGH = 0x02, + PCF50633_MBCS3_TLIM_PLAY = 0x04, + PCF50633_MBCS3_TLIM_CHG = 0x08, + PCF50633_MBCS3_ILIM = 0x10, /* 1: Ibat > Icutoff */ + PCF50633_MBCS3_VLIM = 0x20, /* 1: Vbat == Vmax */ + PCF50633_MBCS3_VBATSTAT = 0x40, /* 1: Vbat > Vbatcond */ + PCF50633_MBCS3_VRES = 0x80, /* 1: Vbat > Vth(RES) */ +}; + +/* this is to be provided by the board implementation */ +extern const u_int8_t pcf50633_initial_regs[__NUM_PCF50633_REGS]; + +void pcf50633_reg_write(u_int8_t reg, u_int8_t val); + +u_int8_t pcf50633_reg_read(u_int8_t reg); + +void pcf50633_reg_set_bit_mask(u_int8_t reg, u_int8_t mask, u_int8_t val); +void pcf50633_reg_clear_bits(u_int8_t reg, u_int8_t bits); + +void pcf50633_charge_autofast(int on); + +#endif /* _PCF50606_H */ + diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c deleted file mode 100644 index acf8b9d5f57..00000000000 --- a/drivers/i2c/chips/tps65010.c +++ /dev/null @@ -1,1072 +0,0 @@ -/* - * tps65010 - driver for tps6501x power management chips - * - * Copyright (C) 2004 Texas Instruments - * Copyright (C) 2004-2005 David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - - -/*-------------------------------------------------------------------------*/ - -#define DRIVER_VERSION "2 May 2005" -#define DRIVER_NAME (tps65010_driver.driver.name) - -MODULE_DESCRIPTION("TPS6501x Power Management Driver"); -MODULE_LICENSE("GPL"); - -static struct i2c_driver tps65010_driver; - -/*-------------------------------------------------------------------------*/ - -/* This driver handles a family of multipurpose chips, which incorporate - * voltage regulators, lithium ion/polymer battery charging, GPIOs, LEDs, - * and other features often needed in portable devices like cell phones - * or digital cameras. - * - * The tps65011 and tps65013 have different voltage settings compared - * to tps65010 and tps65012. The tps65013 has a NO_CHG status/irq. - * All except tps65010 have "wait" mode, possibly defaulted so that - * battery-insert != device-on. - * - * We could distinguish between some models by checking VDCDC1.UVLO or - * other registers, unless they've been changed already after powerup - * as part of board setup by a bootloader. - */ -enum tps_model { - TPS65010, - TPS65011, - TPS65012, - TPS65013, -}; - -struct tps65010 { - struct i2c_client *client; - struct mutex lock; - struct delayed_work work; - struct dentry *file; - unsigned charging:1; - unsigned por:1; - unsigned model:8; - u16 vbus; - unsigned long flags; -#define FLAG_VBUS_CHANGED 0 -#define FLAG_IRQ_ENABLE 1 - - /* copies of last register state */ - u8 chgstatus, regstatus, chgconf; - u8 nmask1, nmask2; - - u8 outmask; - struct gpio_chip chip; - struct platform_device *leds; -}; - -#define POWER_POLL_DELAY msecs_to_jiffies(5000) - -/*-------------------------------------------------------------------------*/ - -#if defined(DEBUG) || defined(CONFIG_DEBUG_FS) - -static void dbg_chgstat(char *buf, size_t len, u8 chgstatus) -{ - snprintf(buf, len, "%02x%s%s%s%s%s%s%s%s\n", - chgstatus, - (chgstatus & TPS_CHG_USB) ? " USB" : "", - (chgstatus & TPS_CHG_AC) ? " AC" : "", - (chgstatus & TPS_CHG_THERM) ? " therm" : "", - (chgstatus & TPS_CHG_TERM) ? " done" : - ((chgstatus & (TPS_CHG_USB|TPS_CHG_AC)) - ? " (charging)" : ""), - (chgstatus & TPS_CHG_TAPER_TMO) ? " taper_tmo" : "", - (chgstatus & TPS_CHG_CHG_TMO) ? " charge_tmo" : "", - (chgstatus & TPS_CHG_PRECHG_TMO) ? " prechg_tmo" : "", - (chgstatus & TPS_CHG_TEMP_ERR) ? " temp_err" : ""); -} - -static void dbg_regstat(char *buf, size_t len, u8 regstatus) -{ - snprintf(buf, len, "%02x %s%s%s%s%s%s%s%s\n", - regstatus, - (regstatus & TPS_REG_ONOFF) ? "off" : "(on)", - (regstatus & TPS_REG_COVER) ? " uncover" : "", - (regstatus & TPS_REG_UVLO) ? " UVLO" : "", - (regstatus & TPS_REG_NO_CHG) ? " NO_CHG" : "", - (regstatus & TPS_REG_PG_LD02) ? " ld02_bad" : "", - (regstatus & TPS_REG_PG_LD01) ? " ld01_bad" : "", - (regstatus & TPS_REG_PG_MAIN) ? " main_bad" : "", - (regstatus & TPS_REG_PG_CORE) ? " core_bad" : ""); -} - -static void dbg_chgconf(int por, char *buf, size_t len, u8 chgconfig) -{ - const char *hibit; - - if (por) - hibit = (chgconfig & TPS_CHARGE_POR) - ? "POR=69ms" : "POR=1sec"; - else - hibit = (chgconfig & TPS65013_AUA) ? "AUA" : ""; - - snprintf(buf, len, "%02x %s%s%s AC=%d%% USB=%dmA %sCharge\n", - chgconfig, hibit, - (chgconfig & TPS_CHARGE_RESET) ? " reset" : "", - (chgconfig & TPS_CHARGE_FAST) ? " fast" : "", - ({int p; switch ((chgconfig >> 3) & 3) { - case 3: p = 100; break; - case 2: p = 75; break; - case 1: p = 50; break; - default: p = 25; break; - }; p; }), - (chgconfig & TPS_VBUS_CHARGING) - ? ((chgconfig & TPS_VBUS_500MA) ? 500 : 100) - : 0, - (chgconfig & TPS_CHARGE_ENABLE) ? "" : "No"); -} - -#endif - -#ifdef DEBUG - -static void show_chgstatus(const char *label, u8 chgstatus) -{ - char buf [100]; - - dbg_chgstat(buf, sizeof buf, chgstatus); - pr_debug("%s: %s %s", DRIVER_NAME, label, buf); -} - -static void show_regstatus(const char *label, u8 regstatus) -{ - char buf [100]; - - dbg_regstat(buf, sizeof buf, regstatus); - pr_debug("%s: %s %s", DRIVER_NAME, label, buf); -} - -static void show_chgconfig(int por, const char *label, u8 chgconfig) -{ - char buf [100]; - - dbg_chgconf(por, buf, sizeof buf, chgconfig); - pr_debug("%s: %s %s", DRIVER_NAME, label, buf); -} - -#else - -static inline void show_chgstatus(const char *label, u8 chgstatus) { } -static inline void show_regstatus(const char *label, u8 chgstatus) { } -static inline void show_chgconfig(int por, const char *label, u8 chgconfig) { } - -#endif - -#ifdef CONFIG_DEBUG_FS - -static int dbg_show(struct seq_file *s, void *_) -{ - struct tps65010 *tps = s->private; - u8 value, v2; - unsigned i; - char buf[100]; - const char *chip; - - switch (tps->model) { - case TPS65010: chip = "tps65010"; break; - case TPS65011: chip = "tps65011"; break; - case TPS65012: chip = "tps65012"; break; - case TPS65013: chip = "tps65013"; break; - default: chip = NULL; break; - } - seq_printf(s, "driver %s\nversion %s\nchip %s\n\n", - DRIVER_NAME, DRIVER_VERSION, chip); - - mutex_lock(&tps->lock); - - /* FIXME how can we tell whether a battery is present? - * likely involves a charge gauging chip (like BQ26501). - */ - - seq_printf(s, "%scharging\n\n", tps->charging ? "" : "(not) "); - - - /* registers for monitoring battery charging and status; note - * that reading chgstat and regstat may ack IRQs... - */ - value = i2c_smbus_read_byte_data(tps->client, TPS_CHGCONFIG); - dbg_chgconf(tps->por, buf, sizeof buf, value); - seq_printf(s, "chgconfig %s", buf); - - value = i2c_smbus_read_byte_data(tps->client, TPS_CHGSTATUS); - dbg_chgstat(buf, sizeof buf, value); - seq_printf(s, "chgstat %s", buf); - value = i2c_smbus_read_byte_data(tps->client, TPS_MASK1); - dbg_chgstat(buf, sizeof buf, value); - seq_printf(s, "mask1 %s", buf); - /* ignore ackint1 */ - - value = i2c_smbus_read_byte_data(tps->client, TPS_REGSTATUS); - dbg_regstat(buf, sizeof buf, value); - seq_printf(s, "regstat %s", buf); - value = i2c_smbus_read_byte_data(tps->client, TPS_MASK2); - dbg_regstat(buf, sizeof buf, value); - seq_printf(s, "mask2 %s\n", buf); - /* ignore ackint2 */ - - (void) schedule_delayed_work(&tps->work, POWER_POLL_DELAY); - - - /* VMAIN voltage, enable lowpower, etc */ - value = i2c_smbus_read_byte_data(tps->client, TPS_VDCDC1); - seq_printf(s, "vdcdc1 %02x\n", value); - - /* VCORE voltage, vibrator on/off */ - value = i2c_smbus_read_byte_data(tps->client, TPS_VDCDC2); - seq_printf(s, "vdcdc2 %02x\n", value); - - /* both LD0s, and their lowpower behavior */ - value = i2c_smbus_read_byte_data(tps->client, TPS_VREGS1); - seq_printf(s, "vregs1 %02x\n\n", value); - - - /* LEDs and GPIOs */ - value = i2c_smbus_read_byte_data(tps->client, TPS_LED1_ON); - v2 = i2c_smbus_read_byte_data(tps->client, TPS_LED1_PER); - seq_printf(s, "led1 %s, on=%02x, per=%02x, %d/%d msec\n", - (value & 0x80) - ? ((v2 & 0x80) ? "on" : "off") - : ((v2 & 0x80) ? "blink" : "(nPG)"), - value, v2, - (value & 0x7f) * 10, (v2 & 0x7f) * 100); - - value = i2c_smbus_read_byte_data(tps->client, TPS_LED2_ON); - v2 = i2c_smbus_read_byte_data(tps->client, TPS_LED2_PER); - seq_printf(s, "led2 %s, on=%02x, per=%02x, %d/%d msec\n", - (value & 0x80) - ? ((v2 & 0x80) ? "on" : "off") - : ((v2 & 0x80) ? "blink" : "off"), - value, v2, - (value & 0x7f) * 10, (v2 & 0x7f) * 100); - - value = i2c_smbus_read_byte_data(tps->client, TPS_DEFGPIO); - v2 = i2c_smbus_read_byte_data(tps->client, TPS_MASK3); - seq_printf(s, "defgpio %02x mask3 %02x\n", value, v2); - - for (i = 0; i < 4; i++) { - if (value & (1 << (4 + i))) - seq_printf(s, " gpio%d-out %s\n", i + 1, - (value & (1 << i)) ? "low" : "hi "); - else - seq_printf(s, " gpio%d-in %s %s %s\n", i + 1, - (value & (1 << i)) ? "hi " : "low", - (v2 & (1 << i)) ? "no-irq" : "irq", - (v2 & (1 << (4 + i))) ? "rising" : "falling"); - } - - mutex_unlock(&tps->lock); - return 0; -} - -static int dbg_tps_open(struct inode *inode, struct file *file) -{ - return single_open(file, dbg_show, inode->i_private); -} - -static const struct file_operations debug_fops = { - .open = dbg_tps_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -#define DEBUG_FOPS &debug_fops - -#else -#define DEBUG_FOPS NULL -#endif - -/*-------------------------------------------------------------------------*/ - -/* handle IRQS in a task context, so we can use I2C calls */ -static void tps65010_interrupt(struct tps65010 *tps) -{ - u8 tmp = 0, mask, poll; - - /* IRQs won't trigger for certain events, but we can get - * others by polling (normally, with external power applied). - */ - poll = 0; - - /* regstatus irqs */ - if (tps->nmask2) { - tmp = i2c_smbus_read_byte_data(tps->client, TPS_REGSTATUS); - mask = tmp ^ tps->regstatus; - tps->regstatus = tmp; - mask &= tps->nmask2; - } else - mask = 0; - if (mask) { - tps->regstatus = tmp; - /* may need to shut something down ... */ - - /* "off" usually means deep sleep */ - if (tmp & TPS_REG_ONOFF) { - pr_info("%s: power off button\n", DRIVER_NAME); -#if 0 - /* REVISIT: this might need its own workqueue - * plus tweaks including deadlock avoidance ... - * also needs to get error handling and probably - * an #ifdef CONFIG_HIBERNATION - */ - hibernate(); -#endif - poll = 1; - } - } - - /* chgstatus irqs */ - if (tps->nmask1) { - tmp = i2c_smbus_read_byte_data(tps->client, TPS_CHGSTATUS); - mask = tmp ^ tps->chgstatus; - tps->chgstatus = tmp; - mask &= tps->nmask1; - } else - mask = 0; - if (mask) { - unsigned charging = 0; - - show_chgstatus("chg/irq", tmp); - if (tmp & (TPS_CHG_USB|TPS_CHG_AC)) - show_chgconfig(tps->por, "conf", tps->chgconf); - - /* Unless it was turned off or disabled, we charge any - * battery whenever there's power available for it - * and the charger hasn't been disabled. - */ - if (!(tps->chgstatus & ~(TPS_CHG_USB|TPS_CHG_AC)) - && (tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC)) - && (tps->chgconf & TPS_CHARGE_ENABLE) - ) { - if (tps->chgstatus & TPS_CHG_USB) { - /* VBUS options are readonly until reconnect */ - if (mask & TPS_CHG_USB) - set_bit(FLAG_VBUS_CHANGED, &tps->flags); - charging = 1; - } else if (tps->chgstatus & TPS_CHG_AC) - charging = 1; - } - if (charging != tps->charging) { - tps->charging = charging; - pr_info("%s: battery %scharging\n", - DRIVER_NAME, charging ? "" : - ((tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC)) - ? "NOT " : "dis")); - } - } - - /* always poll to detect (a) power removal, without tps65013 - * NO_CHG IRQ; or (b) restart of charging after stop. - */ - if ((tps->model != TPS65013 || !tps->charging) - && (tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC))) - poll = 1; - if (poll) - (void) schedule_delayed_work(&tps->work, POWER_POLL_DELAY); - - /* also potentially gpio-in rise or fall */ -} - -/* handle IRQs and polling using keventd for now */ -static void tps65010_work(struct work_struct *work) -{ - struct tps65010 *tps; - - tps = container_of(work, struct tps65010, work.work); - mutex_lock(&tps->lock); - - tps65010_interrupt(tps); - - if (test_and_clear_bit(FLAG_VBUS_CHANGED, &tps->flags)) { - int status; - u8 chgconfig, tmp; - - chgconfig = i2c_smbus_read_byte_data(tps->client, - TPS_CHGCONFIG); - chgconfig &= ~(TPS_VBUS_500MA | TPS_VBUS_CHARGING); - if (tps->vbus == 500) - chgconfig |= TPS_VBUS_500MA | TPS_VBUS_CHARGING; - else if (tps->vbus >= 100) - chgconfig |= TPS_VBUS_CHARGING; - - status = i2c_smbus_write_byte_data(tps->client, - TPS_CHGCONFIG, chgconfig); - - /* vbus update fails unless VBUS is connected! */ - tmp = i2c_smbus_read_byte_data(tps->client, TPS_CHGCONFIG); - tps->chgconf = tmp; - show_chgconfig(tps->por, "update vbus", tmp); - } - - if (test_and_clear_bit(FLAG_IRQ_ENABLE, &tps->flags)) - enable_irq(tps->client->irq); - - mutex_unlock(&tps->lock); -} - -static irqreturn_t tps65010_irq(int irq, void *_tps) -{ - struct tps65010 *tps = _tps; - - disable_irq_nosync(irq); - set_bit(FLAG_IRQ_ENABLE, &tps->flags); - (void) schedule_work(&tps->work.work); - return IRQ_HANDLED; -} - -/*-------------------------------------------------------------------------*/ - -/* offsets 0..3 == GPIO1..GPIO4 - * offsets 4..5 == LED1/nPG, LED2 (we set one of the non-BLINK modes) - * offset 6 == vibrator motor driver - */ -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 if (offset < 6) - tps65010_set_led(offset - 3, value ? ON : OFF); - else - tps65010_set_vib(value); -} - -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 if (offset < 6) - tps65010_set_led(offset - 3, value ? ON : OFF); - else - tps65010_set_vib(value); - - 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); - flush_scheduled_work(); - debugfs_remove(tps->file); - kfree(tps); - i2c_set_clientdata(client, NULL); - the_tps = NULL; - return 0; -} - -static int tps65010_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - 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"); - return -ENODEV; - } - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EINVAL; - - tps = kzalloc(sizeof *tps, GFP_KERNEL); - if (!tps) - return -ENOMEM; - - mutex_init(&tps->lock); - INIT_DELAYED_WORK(&tps->work, tps65010_work); - tps->client = client; - tps->model = id->driver_data; - - /* the IRQ is active low, but many gpio lines can't support that - * so this driver uses falling-edge triggers instead. - */ - if (client->irq > 0) { - status = request_irq(client->irq, tps65010_irq, - IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_FALLING, - DRIVER_NAME, tps); - if (status < 0) { - dev_dbg(&client->dev, "can't get IRQ %d, err %d\n", - client->irq, status); - goto fail1; - } - /* annoying race here, ideally we'd have an option - * to claim the irq now and enable it later. - * FIXME genirq IRQF_NOAUTOEN now solves that ... - */ - disable_irq(client->irq); - set_bit(FLAG_IRQ_ENABLE, &tps->flags); - } else - dev_warn(&client->dev, "IRQ not configured!\n"); - - - switch (tps->model) { - case TPS65010: - case TPS65012: - tps->por = 1; - break; - /* else CHGCONFIG.POR is replaced by AUA, enabling a WAIT mode */ - } - tps->chgconf = i2c_smbus_read_byte_data(client, TPS_CHGCONFIG); - show_chgconfig(tps->por, "conf/init", tps->chgconf); - - show_chgstatus("chg/init", - i2c_smbus_read_byte_data(client, TPS_CHGSTATUS)); - show_regstatus("reg/init", - i2c_smbus_read_byte_data(client, TPS_REGSTATUS)); - - pr_debug("%s: vdcdc1 0x%02x, vdcdc2 %02x, vregs1 %02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(client, TPS_VDCDC1), - i2c_smbus_read_byte_data(client, TPS_VDCDC2), - i2c_smbus_read_byte_data(client, TPS_VREGS1)); - pr_debug("%s: defgpio 0x%02x, mask3 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(client, TPS_DEFGPIO), - i2c_smbus_read_byte_data(client, TPS_MASK3)); - - i2c_set_clientdata(client, tps); - the_tps = tps; - -#if defined(CONFIG_USB_GADGET) && !defined(CONFIG_USB_OTG) - /* USB hosts can't draw VBUS. OTG devices could, later - * when OTG infrastructure enables it. USB peripherals - * could be relying on VBUS while booting, though. - */ - tps->vbus = 100; -#endif - - /* unmask the "interesting" irqs, then poll once to - * kickstart monitoring, initialize shadowed status - * registers, and maybe disable VBUS draw. - */ - tps->nmask1 = ~0; - (void) i2c_smbus_write_byte_data(client, TPS_MASK1, ~tps->nmask1); - - tps->nmask2 = TPS_REG_ONOFF; - if (tps->model == TPS65013) - tps->nmask2 |= TPS_REG_NO_CHG; - (void) i2c_smbus_write_byte_data(client, TPS_MASK2, ~tps->nmask2); - - (void) i2c_smbus_write_byte_data(client, TPS_MASK3, 0x0f - | i2c_smbus_read_byte_data(client, TPS_MASK3)); - - tps65010_work(&tps->work.work); - - 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.dev = &client->dev; - tps->chip.owner = THIS_MODULE; - - 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 = 7; - 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); - return status; -} - -static const struct i2c_device_id tps65010_id[] = { - { "tps65010", TPS65010 }, - { "tps65011", TPS65011 }, - { "tps65012", TPS65012 }, - { "tps65013", TPS65013 }, - { "tps65014", TPS65011 }, /* tps65011 charging at 6.5V max */ - { } -}; -MODULE_DEVICE_TABLE(i2c, tps65010_id); - -static struct i2c_driver tps65010_driver = { - .driver = { - .name = "tps65010", - }, - .probe = tps65010_probe, - .remove = __exit_p(tps65010_remove), - .id_table = tps65010_id, -}; - -/*-------------------------------------------------------------------------*/ - -/* Draw from VBUS: - * 0 mA -- DON'T DRAW (might supply power instead) - * 100 mA -- usb unit load (slowest charge rate) - * 500 mA -- usb high power (fast battery charge) - */ -int tps65010_set_vbus_draw(unsigned mA) -{ - unsigned long flags; - - if (!the_tps) - return -ENODEV; - - /* assumes non-SMP */ - local_irq_save(flags); - if (mA >= 500) - mA = 500; - else if (mA >= 100) - mA = 100; - else - mA = 0; - the_tps->vbus = mA; - if ((the_tps->chgstatus & TPS_CHG_USB) - && test_and_set_bit( - FLAG_VBUS_CHANGED, &the_tps->flags)) { - /* gadget drivers call this in_irq() */ - (void) schedule_work(&the_tps->work.work); - } - local_irq_restore(flags); - - return 0; -} -EXPORT_SYMBOL(tps65010_set_vbus_draw); - -/*-------------------------------------------------------------------------*/ -/* tps65010_set_gpio_out_value parameter: - * gpio: GPIO1, GPIO2, GPIO3 or GPIO4 - * value: LOW or HIGH - */ -int tps65010_set_gpio_out_value(unsigned gpio, unsigned value) -{ - int status; - unsigned defgpio; - - if (!the_tps) - return -ENODEV; - if ((gpio < GPIO1) || (gpio > GPIO4)) - return -EINVAL; - - mutex_lock(&the_tps->lock); - - defgpio = i2c_smbus_read_byte_data(the_tps->client, TPS_DEFGPIO); - - /* Configure GPIO for output */ - defgpio |= 1 << (gpio + 3); - - /* Writing 1 forces a logic 0 on that GPIO and vice versa */ - switch (value) { - case LOW: - defgpio |= 1 << (gpio - 1); /* set GPIO low by writing 1 */ - break; - /* case HIGH: */ - default: - defgpio &= ~(1 << (gpio - 1)); /* set GPIO high by writing 0 */ - break; - } - - status = i2c_smbus_write_byte_data(the_tps->client, - TPS_DEFGPIO, defgpio); - - pr_debug("%s: gpio%dout = %s, defgpio 0x%02x\n", DRIVER_NAME, - gpio, value ? "high" : "low", - i2c_smbus_read_byte_data(the_tps->client, TPS_DEFGPIO)); - - mutex_unlock(&the_tps->lock); - return status; -} -EXPORT_SYMBOL(tps65010_set_gpio_out_value); - -/*-------------------------------------------------------------------------*/ -/* tps65010_set_led parameter: - * led: LED1 or LED2 - * mode: ON, OFF or BLINK - */ -int tps65010_set_led(unsigned led, unsigned mode) -{ - int status; - unsigned led_on, led_per, offs; - - if (!the_tps) - return -ENODEV; - - if (led == LED1) - offs = 0; - else { - offs = 2; - led = LED2; - } - - mutex_lock(&the_tps->lock); - - pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led, - i2c_smbus_read_byte_data(the_tps->client, - TPS_LED1_ON + offs)); - - pr_debug("%s: led%i_per 0x%02x\n", DRIVER_NAME, led, - i2c_smbus_read_byte_data(the_tps->client, - TPS_LED1_PER + offs)); - - switch (mode) { - case OFF: - led_on = 1 << 7; - led_per = 0 << 7; - break; - case ON: - led_on = 1 << 7; - led_per = 1 << 7; - break; - case BLINK: - led_on = 0x30 | (0 << 7); - led_per = 0x08 | (1 << 7); - break; - default: - printk(KERN_ERR "%s: Wrong mode parameter for set_led()\n", - DRIVER_NAME); - mutex_unlock(&the_tps->lock); - return -EINVAL; - } - - status = i2c_smbus_write_byte_data(the_tps->client, - TPS_LED1_ON + offs, led_on); - - if (status != 0) { - printk(KERN_ERR "%s: Failed to write led%i_on register\n", - DRIVER_NAME, led); - mutex_unlock(&the_tps->lock); - return status; - } - - pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led, - i2c_smbus_read_byte_data(the_tps->client, TPS_LED1_ON + offs)); - - status = i2c_smbus_write_byte_data(the_tps->client, - TPS_LED1_PER + offs, led_per); - - if (status != 0) { - printk(KERN_ERR "%s: Failed to write led%i_per register\n", - DRIVER_NAME, led); - mutex_unlock(&the_tps->lock); - return status; - } - - pr_debug("%s: led%i_per 0x%02x\n", DRIVER_NAME, led, - i2c_smbus_read_byte_data(the_tps->client, - TPS_LED1_PER + offs)); - - mutex_unlock(&the_tps->lock); - - return status; -} -EXPORT_SYMBOL(tps65010_set_led); - -/*-------------------------------------------------------------------------*/ -/* tps65010_set_vib parameter: - * value: ON or OFF - */ -int tps65010_set_vib(unsigned value) -{ - int status; - unsigned vdcdc2; - - if (!the_tps) - return -ENODEV; - - mutex_lock(&the_tps->lock); - - vdcdc2 = i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC2); - vdcdc2 &= ~(1 << 1); - if (value) - vdcdc2 |= (1 << 1); - status = i2c_smbus_write_byte_data(the_tps->client, - TPS_VDCDC2, vdcdc2); - - pr_debug("%s: vibrator %s\n", DRIVER_NAME, value ? "on" : "off"); - - mutex_unlock(&the_tps->lock); - return status; -} -EXPORT_SYMBOL(tps65010_set_vib); - -/*-------------------------------------------------------------------------*/ -/* tps65010_set_low_pwr parameter: - * mode: ON or OFF - */ -int tps65010_set_low_pwr(unsigned mode) -{ - int status; - unsigned vdcdc1; - - if (!the_tps) - return -ENODEV; - - mutex_lock(&the_tps->lock); - - pr_debug("%s: %s low_pwr, vdcdc1 0x%02x\n", DRIVER_NAME, - mode ? "enable" : "disable", - i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1)); - - vdcdc1 = i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1); - - switch (mode) { - case OFF: - vdcdc1 &= ~TPS_ENABLE_LP; /* disable ENABLE_LP bit */ - break; - /* case ON: */ - default: - vdcdc1 |= TPS_ENABLE_LP; /* enable ENABLE_LP bit */ - break; - } - - status = i2c_smbus_write_byte_data(the_tps->client, - TPS_VDCDC1, vdcdc1); - - if (status != 0) - printk(KERN_ERR "%s: Failed to write vdcdc1 register\n", - DRIVER_NAME); - else - pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1)); - - mutex_unlock(&the_tps->lock); - - return status; -} -EXPORT_SYMBOL(tps65010_set_low_pwr); - -/*-------------------------------------------------------------------------*/ -/* tps65010_config_vregs1 parameter: - * value to be written to VREGS1 register - * Note: The complete register is written, set all bits you need - */ -int tps65010_config_vregs1(unsigned value) -{ - int status; - - if (!the_tps) - return -ENODEV; - - mutex_lock(&the_tps->lock); - - pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(the_tps->client, TPS_VREGS1)); - - status = i2c_smbus_write_byte_data(the_tps->client, - TPS_VREGS1, value); - - if (status != 0) - printk(KERN_ERR "%s: Failed to write vregs1 register\n", - DRIVER_NAME); - else - pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(the_tps->client, TPS_VREGS1)); - - mutex_unlock(&the_tps->lock); - - return status; -} -EXPORT_SYMBOL(tps65010_config_vregs1); - -/*-------------------------------------------------------------------------*/ -/* tps65013_set_low_pwr parameter: - * mode: ON or OFF - */ - -/* FIXME: Assumes AC or USB power is present. Setting AUA bit is not - required if power supply is through a battery */ - -int tps65013_set_low_pwr(unsigned mode) -{ - int status; - unsigned vdcdc1, chgconfig; - - if (!the_tps || the_tps->por) - return -ENODEV; - - mutex_lock(&the_tps->lock); - - pr_debug("%s: %s low_pwr, chgconfig 0x%02x vdcdc1 0x%02x\n", - DRIVER_NAME, - mode ? "enable" : "disable", - i2c_smbus_read_byte_data(the_tps->client, TPS_CHGCONFIG), - i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1)); - - chgconfig = i2c_smbus_read_byte_data(the_tps->client, TPS_CHGCONFIG); - vdcdc1 = i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1); - - switch (mode) { - case OFF: - chgconfig &= ~TPS65013_AUA; /* disable AUA bit */ - vdcdc1 &= ~TPS_ENABLE_LP; /* disable ENABLE_LP bit */ - break; - /* case ON: */ - default: - chgconfig |= TPS65013_AUA; /* enable AUA bit */ - vdcdc1 |= TPS_ENABLE_LP; /* enable ENABLE_LP bit */ - break; - } - - status = i2c_smbus_write_byte_data(the_tps->client, - TPS_CHGCONFIG, chgconfig); - if (status != 0) { - printk(KERN_ERR "%s: Failed to write chconfig register\n", - DRIVER_NAME); - mutex_unlock(&the_tps->lock); - return status; - } - - chgconfig = i2c_smbus_read_byte_data(the_tps->client, TPS_CHGCONFIG); - the_tps->chgconf = chgconfig; - show_chgconfig(0, "chgconf", chgconfig); - - status = i2c_smbus_write_byte_data(the_tps->client, - TPS_VDCDC1, vdcdc1); - - if (status != 0) - printk(KERN_ERR "%s: Failed to write vdcdc1 register\n", - DRIVER_NAME); - else - pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1)); - - mutex_unlock(&the_tps->lock); - - return status; -} -EXPORT_SYMBOL(tps65013_set_low_pwr); - -/*-------------------------------------------------------------------------*/ - -static int __init tps_init(void) -{ - u32 tries = 3; - int status = -ENODEV; - - printk(KERN_INFO "%s: version %s\n", DRIVER_NAME, DRIVER_VERSION); - - /* some boards have startup glitches */ - while (tries--) { - status = i2c_add_driver(&tps65010_driver); - if (the_tps) - break; - i2c_del_driver(&tps65010_driver); - if (!tries) { - printk(KERN_ERR "%s: no chip?\n", DRIVER_NAME); - return -ENODEV; - } - pr_debug("%s: re-probe ...\n", DRIVER_NAME); - msleep(10); - } - - return status; -} -/* NOTE: this MUST be initialized before the other parts of the system - * that rely on it ... but after the i2c bus on which this relies. - * That is, much earlier than on PC-type systems, which don't often use - * I2C as a core system bus. - */ -subsys_initcall(tps_init); - -static void __exit tps_exit(void) -{ - i2c_del_driver(&tps65010_driver); -} -module_exit(tps_exit); - diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index ceb473f6e29..cdf067e58d3 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -470,7 +470,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) pr_debug("I2C adapter driver [%s] forgot to specify " "physical device\n", adap->name); } - sprintf(adap->dev.bus_id, "i2c-%d", adap->nr); + dev_set_name(&adap->dev, "i2c-%d", adap->nr); adap->dev.release = &i2c_adapter_dev_release; adap->dev.class = &i2c_adapter_class; res = device_register(&adap->dev); @@ -642,7 +642,7 @@ int i2c_del_adapter(struct i2c_adapter *adap) /* detach any active clients. This must be done first, because * it can fail; in which case we give up. */ - list_for_each_entry_safe(client, _n, &adap->clients, list) { + list_for_each_entry_safe_reverse(client, _n, &adap->clients, list) { struct i2c_driver *driver; driver = client->driver; @@ -856,8 +856,8 @@ int i2c_attach_client(struct i2c_client *client) } else client->dev.release = i2c_client_dev_release; - snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id), - "%d-%04x", i2c_adapter_id(adapter), client->addr); + dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adapter), + client->addr); res = device_register(&client->dev); if (res) goto out_err; @@ -867,7 +867,7 @@ int i2c_attach_client(struct i2c_client *client) mutex_unlock(&adapter->clist_lock); dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", - client->name, client->dev.bus_id); + client->name, dev_name(&client->dev)); if (adapter->client_register) { if (adapter->client_register(client)) { -- cgit v1.2.3