diff options
-rw-r--r-- | drivers/mfd/Makefile | 1 | ||||
-rw-r--r-- | drivers/mfd/max8907c-irq.c | 359 | ||||
-rw-r--r-- | drivers/mfd/max8907c.c | 165 | ||||
-rw-r--r-- | include/linux/mfd/max8907c.h | 56 |
4 files changed, 507 insertions, 74 deletions
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index ae6c2e7f8151..4bb7f8acc81b 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -103,3 +103,4 @@ obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o obj-$(CONFIG_MFD_MAX8907C) += max8907c.o +obj-$(CONFIG_MFD_MAX8907C) += max8907c-irq.o diff --git a/drivers/mfd/max8907c-irq.c b/drivers/mfd/max8907c-irq.c new file mode 100644 index 000000000000..e9773c0fe00e --- /dev/null +++ b/drivers/mfd/max8907c-irq.c @@ -0,0 +1,359 @@ +/* + * Battery driver for Maxim MAX8907C + * + * Copyright (c) 2011, NVIDIA Corporation. + * Based on driver/mfd/max8925-core.c, Copyright (C) 2009-2010 Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/mfd/core.h> +#include <linux/mfd/max8907c.h> + +struct max8907c_irq_data { + int reg; + int mask_reg; + int enable; /* enable or not */ + int offs; /* bit offset in mask register */ + bool is_rtc; +}; + +static struct max8907c_irq_data max8907c_irqs[] = { + [MAX8907C_IRQ_VCHG_DC_OVP] = { + .reg = MAX8907C_REG_CHG_IRQ1, + .mask_reg = MAX8907C_REG_CHG_IRQ1_MASK, + .offs = 1 << 0, + }, + [MAX8907C_IRQ_VCHG_DC_F] = { + .reg = MAX8907C_REG_CHG_IRQ1, + .mask_reg = MAX8907C_REG_CHG_IRQ1_MASK, + .offs = 1 << 1, + }, + [MAX8907C_IRQ_VCHG_DC_R] = { + .reg = MAX8907C_REG_CHG_IRQ1, + .mask_reg = MAX8907C_REG_CHG_IRQ1_MASK, + .offs = 1 << 2, + }, + [MAX8907C_IRQ_VCHG_THM_OK_R] = { + .reg = MAX8907C_REG_CHG_IRQ2, + .mask_reg = MAX8907C_REG_CHG_IRQ2_MASK, + .offs = 1 << 0, + }, + [MAX8907C_IRQ_VCHG_THM_OK_F] = { + .reg = MAX8907C_REG_CHG_IRQ2, + .mask_reg = MAX8907C_REG_CHG_IRQ2_MASK, + .offs = 1 << 1, + }, + [MAX8907C_IRQ_VCHG_MBATTLOW_F] = { + .reg = MAX8907C_REG_CHG_IRQ2, + .mask_reg = MAX8907C_REG_CHG_IRQ2_MASK, + .offs = 1 << 2, + }, + [MAX8907C_IRQ_VCHG_MBATTLOW_R] = { + .reg = MAX8907C_REG_CHG_IRQ2, + .mask_reg = MAX8907C_REG_CHG_IRQ2_MASK, + .offs = 1 << 3, + }, + [MAX8907C_IRQ_VCHG_RST] = { + .reg = MAX8907C_REG_CHG_IRQ2, + .mask_reg = MAX8907C_REG_CHG_IRQ2_MASK, + .offs = 1 << 4, + }, + [MAX8907C_IRQ_VCHG_DONE] = { + .reg = MAX8907C_REG_CHG_IRQ2, + .mask_reg = MAX8907C_REG_CHG_IRQ2_MASK, + .offs = 1 << 5, + }, + [MAX8907C_IRQ_VCHG_TOPOFF] = { + .reg = MAX8907C_REG_CHG_IRQ2, + .mask_reg = MAX8907C_REG_CHG_IRQ2_MASK, + .offs = 1 << 6, + }, + [MAX8907C_IRQ_VCHG_TMR_FAULT] = { + .reg = MAX8907C_REG_CHG_IRQ2, + .mask_reg = MAX8907C_REG_CHG_IRQ2_MASK, + .offs = 1 << 7, + }, + [MAX8907C_IRQ_GPM_RSTIN] = { + .reg = MAX8907C_REG_ON_OFF_IRQ1, + .mask_reg = MAX8907C_REG_ON_OFF_IRQ1_MASK, + .offs = 1 << 0, + }, + [MAX8907C_IRQ_GPM_MPL] = { + .reg = MAX8907C_REG_ON_OFF_IRQ1, + .mask_reg = MAX8907C_REG_ON_OFF_IRQ1_MASK, + .offs = 1 << 1, + }, + [MAX8907C_IRQ_GPM_SW_3SEC] = { + .reg = MAX8907C_REG_ON_OFF_IRQ1, + .mask_reg = MAX8907C_REG_ON_OFF_IRQ1_MASK, + .offs = 1 << 2, + }, + [MAX8907C_IRQ_GPM_EXTON_F] = { + .reg = MAX8907C_REG_ON_OFF_IRQ1, + .mask_reg = MAX8907C_REG_ON_OFF_IRQ1_MASK, + .offs = 1 << 3, + }, + [MAX8907C_IRQ_GPM_EXTON_R] = { + .reg = MAX8907C_REG_ON_OFF_IRQ1, + .mask_reg = MAX8907C_REG_ON_OFF_IRQ1_MASK, + .offs = 1 << 4, + }, + [MAX8907C_IRQ_GPM_SW_1SEC] = { + .reg = MAX8907C_REG_ON_OFF_IRQ1, + .mask_reg = MAX8907C_REG_ON_OFF_IRQ1_MASK, + .offs = 1 << 5, + }, + [MAX8907C_IRQ_GPM_SW_F] = { + .reg = MAX8907C_REG_ON_OFF_IRQ1, + .mask_reg = MAX8907C_REG_ON_OFF_IRQ1_MASK, + .offs = 1 << 6, + }, + [MAX8907C_IRQ_GPM_SW_R] = { + .reg = MAX8907C_REG_ON_OFF_IRQ1, + .mask_reg = MAX8907C_REG_ON_OFF_IRQ1_MASK, + .offs = 1 << 7, + }, + [MAX8907C_IRQ_GPM_SYSCKEN_F] = { + .reg = MAX8907C_REG_ON_OFF_IRQ2, + .mask_reg = MAX8907C_REG_ON_OFF_IRQ2_MASK, + .offs = 1 << 0, + }, + [MAX8907C_IRQ_GPM_SYSCKEN_R] = { + .reg = MAX8907C_REG_ON_OFF_IRQ2, + .mask_reg = MAX8907C_REG_ON_OFF_IRQ2_MASK, + .offs = 1 << 1, + }, + [MAX8907C_IRQ_RTC_ALARM1] = { + .reg = MAX8907C_REG_RTC_IRQ, + .mask_reg = MAX8907C_REG_RTC_IRQ_MASK, + .offs = 1 << 2, + .is_rtc = true, + }, + [MAX8907C_IRQ_RTC_ALARM0] = { + .reg = MAX8907C_REG_RTC_IRQ, + .mask_reg = MAX8907C_REG_RTC_IRQ_MASK, + .offs = 1 << 3, + .is_rtc = true, + }, +}; + +static inline struct max8907c_irq_data *irq_to_max8907c(struct max8907c *chip, + int irq) +{ + return &max8907c_irqs[irq - chip->irq_base]; +} + +static irqreturn_t max8907c_irq(int irq, void *data) +{ + struct max8907c *chip = data; + struct max8907c_irq_data *irq_data; + struct i2c_client *i2c; + int read_reg = -1, value = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(max8907c_irqs); i++) { + irq_data = &max8907c_irqs[i]; + + if (irq_data->is_rtc) + i2c = chip->i2c_rtc; + else + i2c = chip->i2c_power; + + if (read_reg != irq_data->reg) { + read_reg = irq_data->reg; + value = max8907c_reg_read(i2c, irq_data->reg); + } + + if (value & irq_data->enable) + handle_nested_irq(chip->irq_base + i); + } + return IRQ_HANDLED; +} + +static void max8907c_irq_lock(unsigned int irq) +{ + struct max8907c *chip = get_irq_chip_data(irq); + + mutex_lock(&chip->irq_lock); +} + +static void max8907c_irq_sync_unlock(unsigned int irq) +{ + struct max8907c *chip = get_irq_chip_data(irq); + struct max8907c_irq_data *irq_data; + static unsigned char cache_chg[2] = {0xff, 0xff}; + static unsigned char cache_on[2] = {0xff, 0xff}; + static unsigned char cache_rtc = 0xff; + unsigned char irq_chg[2], irq_on[2]; + unsigned char irq_rtc; + int i; + + /* Load cached value. In initial, all IRQs are masked */ + irq_chg[0] = cache_chg[0]; + irq_chg[1] = cache_chg[1]; + irq_on[0] = cache_on[0]; + irq_on[1] = cache_on[1]; + irq_rtc = cache_rtc; + for (i = 0; i < ARRAY_SIZE(max8907c_irqs); i++) { + irq_data = &max8907c_irqs[i]; + /* 1 -- disable, 0 -- enable */ + switch (irq_data->mask_reg) { + case MAX8907C_REG_CHG_IRQ1_MASK: + irq_chg[0] &= ~irq_data->enable; + break; + case MAX8907C_REG_CHG_IRQ2_MASK: + irq_chg[1] &= ~irq_data->enable; + break; + case MAX8907C_REG_ON_OFF_IRQ1_MASK: + irq_on[0] &= ~irq_data->enable; + break; + case MAX8907C_REG_ON_OFF_IRQ2_MASK: + irq_on[1] &= ~irq_data->enable; + break; + case MAX8907C_REG_RTC_IRQ_MASK: + irq_rtc &= ~irq_data->enable; + break; + default: + dev_err(chip->dev, "wrong IRQ\n"); + break; + } + } + /* update mask into registers */ + if (cache_chg[0] != irq_chg[0]) { + cache_chg[0] = irq_chg[0]; + max8907c_reg_write(chip->i2c_power, MAX8907C_REG_CHG_IRQ1_MASK, + irq_chg[0]); + } + if (cache_chg[1] != irq_chg[1]) { + cache_chg[1] = irq_chg[1]; + max8907c_reg_write(chip->i2c_power, MAX8907C_REG_CHG_IRQ2_MASK, + irq_chg[1]); + } + if (cache_on[0] != irq_on[0]) { + cache_on[0] = irq_on[0]; + max8907c_reg_write(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ1_MASK, + irq_on[0]); + } + if (cache_on[1] != irq_on[1]) { + cache_on[1] = irq_on[1]; + max8907c_reg_write(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ2_MASK, + irq_on[1]); + } + if (cache_rtc != irq_rtc) { + cache_rtc = irq_rtc; + max8907c_reg_write(chip->i2c_rtc, MAX8907C_REG_RTC_IRQ_MASK, + irq_rtc); + } + + mutex_unlock(&chip->irq_lock); +} + +static void max8907c_irq_enable(unsigned int irq) +{ + struct max8907c *chip = get_irq_chip_data(irq); + max8907c_irqs[irq - chip->irq_base].enable + = max8907c_irqs[irq - chip->irq_base].offs; +} + +static void max8907c_irq_disable(unsigned int irq) +{ + struct max8907c *chip = get_irq_chip_data(irq); + max8907c_irqs[irq - chip->irq_base].enable = 0; +} + +static struct irq_chip max8907c_irq_chip = { + .name = "max8907c", + .bus_lock = max8907c_irq_lock, + .bus_sync_unlock = max8907c_irq_sync_unlock, + .enable = max8907c_irq_enable, + .disable = max8907c_irq_disable, +}; + +int max8907c_irq_init(struct max8907c *chip, int irq, int irq_base) +{ + unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; + struct irq_desc *desc; + int i, ret; + int __irq; + + if (!irq_base || !irq) { + dev_warn(chip->dev, "No interrupt support\n"); + return -EINVAL; + } + /* clear all interrupts */ + max8907c_reg_read(chip->i2c_power, MAX8907C_REG_CHG_IRQ1); + max8907c_reg_read(chip->i2c_power, MAX8907C_REG_CHG_IRQ2); + max8907c_reg_read(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ1); + max8907c_reg_read(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ2); + max8907c_reg_read(chip->i2c_rtc, MAX8907C_REG_RTC_IRQ); + /* mask all interrupts */ + max8907c_reg_write(chip->i2c_rtc, MAX8907C_REG_ALARM0_CNTL, 0); + max8907c_reg_write(chip->i2c_rtc, MAX8907C_REG_ALARM1_CNTL, 0); + max8907c_reg_write(chip->i2c_power, MAX8907C_REG_CHG_IRQ1_MASK, 0xff); + max8907c_reg_write(chip->i2c_power, MAX8907C_REG_CHG_IRQ2_MASK, 0xff); + max8907c_reg_write(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ1_MASK, 0xff); + max8907c_reg_write(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ2_MASK, 0xff); + max8907c_reg_write(chip->i2c_rtc, MAX8907C_REG_RTC_IRQ_MASK, 0xff); + + mutex_init(&chip->irq_lock); + chip->core_irq = irq; + chip->irq_base = irq_base; + desc = irq_to_desc(chip->core_irq); + + /* register with genirq */ + for (i = 0; i < ARRAY_SIZE(max8907c_irqs); i++) { + __irq = i + chip->irq_base; + set_irq_chip_data(__irq, chip); + set_irq_chip_and_handler(__irq, &max8907c_irq_chip, + handle_edge_irq); + set_irq_nested_thread(__irq, 1); +#ifdef CONFIG_ARM + set_irq_flags(__irq, IRQF_VALID); +#else + set_irq_noprobe(__irq); +#endif + } + + ret = request_threaded_irq(irq, NULL, max8907c_irq, flags, + "max8907c", chip); + if (ret) { + dev_err(chip->dev, "Failed to request core IRQ: %d\n", ret); + chip->core_irq = 0; + } + + return ret; +} + +int max8907c_suspend(struct i2c_client *i2c, pm_message_t state) +{ + struct max8907c *max8907c = i2c_get_clientdata(i2c); + + disable_irq(max8907c->core_irq); + + return 0; +} + +int max8907c_resume(struct i2c_client *i2c) +{ + struct max8907c *max8907c = i2c_get_clientdata(i2c); + + enable_irq(max8907c->core_irq); + + return 0; +} + +void max8907c_irq_free(struct max8907c *chip) +{ + if (chip->core_irq) + free_irq(chip->core_irq, chip); +} + diff --git a/drivers/mfd/max8907c.c b/drivers/mfd/max8907c.c index 0ceccbab7e37..8475c4be50e9 100644 --- a/drivers/mfd/max8907c.c +++ b/drivers/mfd/max8907c.c @@ -17,20 +17,57 @@ static struct mfd_cell cells[] = { {.name = "max8907-regulator",}, + {.name = "max8907c-rtc",}, }; -int max8907c_reg_read(struct device *dev, u8 reg) +static int max8907c_i2c_read(struct i2c_client *i2c, u8 reg, u8 count, u8 *dest) { - struct i2c_client *i2c = to_i2c_client(dev); - struct max8907c *max8907c = dev_get_drvdata(dev); - u8 val; - int ret; + struct i2c_msg xfer[2]; + int ret = 0; - mutex_lock(&max8907c->io_lock); + xfer[0].addr = i2c->addr; + xfer[0].flags = I2C_M_NOSTART; + xfer[0].len = 1; + xfer[0].buf = ® - ret = max8907c->read_dev(i2c, reg, 1, &val); + xfer[1].addr = i2c->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = count; + xfer[1].buf = dest; + + ret = i2c_transfer(i2c->adapter, xfer, 2); + if (ret < 0) + return ret; + if (ret != 2) + return -EIO; + + return 0; +} + +static int max8907c_i2c_write(struct i2c_client *i2c, u8 reg, u8 count, const u8 *src) +{ + u8 msg[0x100 + 1]; + int ret = 0; + + msg[0] = reg; + memcpy(&msg[1], src, count); + + ret = i2c_master_send(i2c, msg, count + 1); + if (ret < 0) + return ret; + if (ret != count + 1) + return -EIO; + + return 0; +} + +int max8907c_reg_read(struct i2c_client *i2c, u8 reg) +{ + int ret; + u8 val; + + ret = max8907c_i2c_read(i2c, reg, 1, &val); - mutex_unlock(&max8907c->io_lock); pr_debug("max8907c: reg read reg=%x, val=%x\n", (unsigned int)reg, (unsigned int)val); @@ -40,43 +77,72 @@ int max8907c_reg_read(struct device *dev, u8 reg) } EXPORT_SYMBOL_GPL(max8907c_reg_read); -int max8907c_reg_write(struct device *dev, u8 reg, u8 val) +int max8907c_reg_bulk_read(struct i2c_client *i2c, u8 reg, u8 count, u8 *val) { - struct i2c_client *i2c = to_i2c_client(dev); - struct max8907c *max8907c = dev_get_drvdata(dev); + int ret; + + ret = max8907c_i2c_read(i2c, reg, count, val); + + pr_debug("max8907c: reg read reg=%x, val=%x\n", + (unsigned int)reg, (unsigned int)*val); + + if (ret != 0) + pr_err("Failed to read max8907c I2C driver: %d\n", ret); + return ret; +} +EXPORT_SYMBOL_GPL(max8907c_reg_bulk_read); + +int max8907c_reg_write(struct i2c_client *i2c, u8 reg, u8 val) +{ + struct max8907c *max8907c = i2c_get_clientdata(i2c); int ret; pr_debug("max8907c: reg write reg=%x, val=%x\n", (unsigned int)reg, (unsigned int)val); + mutex_lock(&max8907c->io_lock); + ret = max8907c_i2c_write(i2c, reg, 1, &val); + mutex_unlock(&max8907c->io_lock); + + if (ret != 0) + pr_err("Failed to write max8907c I2C driver: %d\n", ret); + return ret; +} +EXPORT_SYMBOL_GPL(max8907c_reg_write); - ret = max8907c->write_dev(i2c, reg, 1, &val); +int max8907c_reg_bulk_write(struct i2c_client *i2c, u8 reg, u8 count, u8 *val) +{ + struct max8907c *max8907c = i2c_get_clientdata(i2c); + int ret; + pr_debug("max8907c: reg write reg=%x, val=%x\n", + (unsigned int)reg, (unsigned int)*val); + + mutex_lock(&max8907c->io_lock); + ret = max8907c_i2c_write(i2c, reg, count, val); mutex_unlock(&max8907c->io_lock); if (ret != 0) pr_err("Failed to write max8907c I2C driver: %d\n", ret); return ret; } -EXPORT_SYMBOL_GPL(max8907c_reg_write); +EXPORT_SYMBOL_GPL(max8907c_reg_bulk_write); -int max8907c_set_bits(struct device *dev, u8 reg, u8 mask, u8 val) +int max8907c_set_bits(struct i2c_client *i2c, u8 reg, u8 mask, u8 val) { - struct i2c_client *i2c = to_i2c_client(dev); - struct max8907c *max8907c = dev_get_drvdata(dev); + struct max8907c *max8907c = i2c_get_clientdata(i2c); u8 tmp; int ret; pr_debug("max8907c: reg write reg=%02X, val=%02X, mask=%02X\n", (unsigned int)reg, (unsigned int)val, (unsigned int)mask); - mutex_lock(&max8907c->io_lock); - ret = max8907c->read_dev(i2c, reg, 1, &tmp); + mutex_lock(&max8907c->io_lock); + ret = max8907c_i2c_read(i2c, reg, 1, &tmp); if (ret == 0) { val = (tmp & ~mask) | (val & mask); - ret = max8907c->write_dev(i2c, reg, 1, &val); + ret = max8907c_i2c_write(i2c, reg, 1, &val); } - mutex_unlock(&max8907c->io_lock); if (ret != 0) @@ -85,49 +151,6 @@ int max8907c_set_bits(struct device *dev, u8 reg, u8 mask, u8 val) } EXPORT_SYMBOL_GPL(max8907c_set_bits); -static int max8907c_i2c_read(void *io_data, u8 reg, u8 count, u8 * dest) -{ - struct i2c_client *i2c = (struct i2c_client *)io_data; - struct i2c_msg xfer[2]; - int ret = 0; - - xfer[0].addr = i2c->addr; - xfer[0].flags = I2C_M_NOSTART; - xfer[0].len = 1; - xfer[0].buf = ® - - xfer[1].addr = i2c->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = count; - xfer[1].buf = dest; - - ret = i2c_transfer(i2c->adapter, xfer, 2); - if (ret < 0) - return ret; - if (ret != 2) - return -EIO; - - return 0; -} - -static int max8907c_i2c_write(void *io_data, u8 reg, u8 count, const u8 * src) -{ - struct i2c_client *i2c = (struct i2c_client *)io_data; - u8 msg[0x100 + 1]; - int ret = 0; - - msg[0] = reg; - memcpy(&msg[1], src, count); - - ret = i2c_master_send(i2c, msg, count + 1); - if (ret < 0) - return ret; - if (ret != count + 1) - return -EIO; - - return 0; -} - static int max8907c_remove_subdev(struct device *dev, void *unused) { platform_device_unregister(to_platform_device(dev)); @@ -177,11 +200,15 @@ static int max8907c_i2c_probe(struct i2c_client *i2c, if (max8907c == NULL) return -ENOMEM; - max8907c->read_dev = max8907c_i2c_read; - max8907c->write_dev = max8907c_i2c_write; max8907c->dev = &i2c->dev; + dev_set_drvdata(max8907c->dev, max8907c); + + max8907c->i2c_power = i2c; i2c_set_clientdata(i2c, max8907c); + max8907c->i2c_rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR); + i2c_set_clientdata(max8907c->i2c_rtc, max8907c); + mutex_init(&max8907c->io_lock); for (i = 0; i < ARRAY_SIZE(cells); i++) @@ -189,11 +216,14 @@ static int max8907c_i2c_probe(struct i2c_client *i2c, ret = mfd_add_devices(max8907c->dev, -1, cells, ARRAY_SIZE(cells), NULL, 0); if (ret != 0) { + i2c_unregister_device(max8907c->i2c_rtc); kfree(max8907c); pr_debug("max8907c: failed to add MFD devices %X\n", ret); return ret; } + max8907c_irq_init(max8907c, i2c->irq, pdata->irq_base); + ret = max8097c_add_subdevs(max8907c, pdata); return ret; @@ -203,7 +233,10 @@ static int max8907c_i2c_remove(struct i2c_client *i2c) { struct max8907c *max8907c = i2c_get_clientdata(i2c); + max8907c_remove_subdevs(max8907c); + i2c_unregister_device(max8907c->i2c_rtc); mfd_remove_devices(max8907c->dev); + max8907c_irq_free(max8907c); kfree(max8907c); return 0; @@ -223,6 +256,8 @@ static struct i2c_driver max8907c_i2c_driver = { }, .probe = max8907c_i2c_probe, .remove = max8907c_i2c_remove, + .suspend = max8907c_suspend, + .resume = max8907c_resume, .id_table = max8907c_i2c_id, }; diff --git a/include/linux/mfd/max8907c.h b/include/linux/mfd/max8907c.h index c78849a32860..d4d62d4a6421 100644 --- a/include/linux/mfd/max8907c.h +++ b/include/linux/mfd/max8907c.h @@ -145,7 +145,7 @@ #define MAX8907C_REG_RTC_STATUS 0x1A #define MAX8907C_REG_RTC_CNTL 0x1B #define MAX8907C_REG_RTC_IRQ 0x1C -#define MAX8907C_REG_IRQ_IRQ_MASK 0x1D +#define MAX8907C_REG_RTC_IRQ_MASK 0x1D #define MAX8907C_REG_MPL_CNTL 0x1E /* ADC and Touch Screen Controller register map */ @@ -162,22 +162,60 @@ #define MAX8907C_MASK_OUT5V_ENSRC 0x0E #define MAX8907C_MASK_OUT5V_EN 0x01 -struct max8907c { - struct device *dev; +#define RTC_I2C_ADDR 0x68 - int (*read_dev) (void *io_data, u8 reg, u8 count, u8 * dst); - int (*write_dev) (void *io_data, u8 reg, u8 count, const u8 * src); +/* IRQ definitions */ +enum { + MAX8907C_IRQ_VCHG_DC_OVP, + MAX8907C_IRQ_VCHG_DC_F, + MAX8907C_IRQ_VCHG_DC_R, + MAX8907C_IRQ_VCHG_THM_OK_R, + MAX8907C_IRQ_VCHG_THM_OK_F, + MAX8907C_IRQ_VCHG_MBATTLOW_F, + MAX8907C_IRQ_VCHG_MBATTLOW_R, + MAX8907C_IRQ_VCHG_RST, + MAX8907C_IRQ_VCHG_DONE, + MAX8907C_IRQ_VCHG_TOPOFF, + MAX8907C_IRQ_VCHG_TMR_FAULT, + MAX8907C_IRQ_GPM_RSTIN, + MAX8907C_IRQ_GPM_MPL, + MAX8907C_IRQ_GPM_SW_3SEC, + MAX8907C_IRQ_GPM_EXTON_F, + MAX8907C_IRQ_GPM_EXTON_R, + MAX8907C_IRQ_GPM_SW_1SEC, + MAX8907C_IRQ_GPM_SW_F, + MAX8907C_IRQ_GPM_SW_R, + MAX8907C_IRQ_GPM_SYSCKEN_F, + MAX8907C_IRQ_GPM_SYSCKEN_R, + MAX8907C_IRQ_RTC_ALARM1, + MAX8907C_IRQ_RTC_ALARM0, + MAX8907C_NR_IRQS, +}; - struct mutex io_lock; +struct max8907c { + struct device *dev; + struct mutex io_lock; + struct mutex irq_lock; + struct i2c_client *i2c_power; + struct i2c_client *i2c_rtc; + int irq_base; + int core_irq; }; struct max8907c_platform_data { int num_subdevs; struct platform_device **subdevs; + int irq_base; }; -int max8907c_reg_read(struct device *dev, u8 reg); -int max8907c_reg_write(struct device *dev, u8 reg, u8 val); -int max8907c_set_bits(struct device *dev, u8 reg, u8 mask, u8 val); +int max8907c_reg_read(struct i2c_client *i2c, u8 reg); +int max8907c_reg_bulk_read(struct i2c_client *i2c, u8 reg, u8 count, u8 *val); +int max8907c_reg_write(struct i2c_client *i2c, u8 reg, u8 val); +int max8907c_reg_bulk_write(struct i2c_client *i2c, u8 reg, u8 count, u8 *val); +int max8907c_set_bits(struct i2c_client *i2c, u8 reg, u8 mask, u8 val); +int max8907c_irq_init(struct max8907c *chip, int irq, int irq_base); +void max8907c_irq_free(struct max8907c *chip); +int max8907c_suspend(struct i2c_client *i2c, pm_message_t state); +int max8907c_resume(struct i2c_client *i2c); #endif |