diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2012-02-01 14:16:24 +0100 |
---|---|---|
committer | Philippe Langlais <philippe.langlais@linaro.org> | 2012-03-19 08:51:26 +0100 |
commit | 81b5bd21a0570c872e214e5f4ee39bf22fc58943 (patch) | |
tree | 20a95f8cf66bc6c4b5bdcb651d0a334eb0ca9dc1 /drivers | |
parent | 772c26bae7719a1081d8feee71781f3a89cd0754 (diff) |
mfd/ab8500: add version detection and enforcing
There are currently four different versions of the AB8500
around: AB8500, AB8505, AB9540 and AB8540. Unfortunately:
- Some of the chips (AB8500, AB8505, AB9540) cannot read
the AB8500_REV_REG register but return errors
- Some of them have the same ID value in the hardware
register AB8500_REV_REV, for example the first versions
of AB8505 and AB9540 have 0xFF in this register -
just like the AB8500.
So we need to be able to enforce a certain version from
the platform. We do this by using the id of the platform
device that provides the read/write functions.
Cc: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Maxime Coquelin <maxime.coquelin@stericsson.com>
Signed-off-by: Alex Macro <alex.macro@stericsson.com>
Signed-off-by: Michel Jaouen <michel.jaouen@stericsson.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Change-Id: I87be719fd88c71356bb7b67374f957205b9e00fe
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/47740
Reviewed-by: Linus WALLEIJ <linus.walleij@stericsson.com>
Tested-by: Linus WALLEIJ <linus.walleij@stericsson.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mfd/ab8500-core.c | 63 | ||||
-rw-r--r-- | drivers/mfd/ab8500-i2c.c | 15 |
2 files changed, 55 insertions, 23 deletions
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 8f35a4862e3..6b197fa900a 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -90,6 +90,7 @@ #define AB8500_IT_MASK24_REG 0x57 #define AB8500_REV_REG 0x80 +#define AB8500_IC_NAME_REG 0x82 #define AB8500_SWITCH_OFF_STATUS 0x00 #define AB8500_TURN_ON_STATUS 0x00 @@ -108,6 +109,13 @@ static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = { 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, }; +static const char ab8500_version_str[][7] = { + [AB8500_VERSION_AB8500] = "AB8500", + [AB8500_VERSION_AB8505] = "AB8505", + [AB8500_VERSION_AB9540] = "AB9540", + [AB8500_VERSION_AB8540] = "AB8540", +}; + static int ab8500_get_chip_id(struct device *dev) { struct ab8500 *ab8500; @@ -260,9 +268,12 @@ static void ab8500_irq_sync_unlock(struct irq_data *data) if (new == old) continue; - /* Interrupt register 12 doesn't exist prior to version 2.0 */ - if (ab8500_irq_regoffset[i] == 11 && - ab8500->chip_id < AB8500_CUT2P0) + /* + * Interrupt register 12 doesn't exist prior to AB8500 version + * 2.0 + */ + if (ab8500->irq_reg_offset[i] == 11 && + is_ab8500_1p1_or_earlier(ab8500)) continue; ab8500->oldmask[i] = new; @@ -315,8 +326,11 @@ static irqreturn_t ab8500_irq(int irq, void *dev) int status; u8 value; - /* Interrupt register 12 doesn't exist prior to version 2.0 */ - if (regoffset == 11 && ab8500->chip_id < AB8500_CUT2P0) + /* + * Interrupt register 12 doesn't exist prior to AB8500 version + * 2.0 + */ + if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500)) continue; status = get_register_interruptible(ab8500, AB8500_INTERRUPT, @@ -867,7 +881,7 @@ static struct attribute_group ab8500_attr_group = { .attrs = ab8500_sysfs_entries, }; -int __devinit ab8500_init(struct ab8500 *ab8500) +int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version) { struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev); int ret; @@ -880,25 +894,29 @@ int __devinit ab8500_init(struct ab8500 *ab8500) mutex_init(&ab8500->lock); mutex_init(&ab8500->irq_lock); + if (version != AB8500_VERSION_UNDEFINED) + ab8500->version = version; + else { + ret = get_register_interruptible(ab8500, AB8500_MISC, + AB8500_IC_NAME_REG, &value); + if (ret < 0) + return ret; + + ab8500->version = value; + } + ret = get_register_interruptible(ab8500, AB8500_MISC, AB8500_REV_REG, &value); if (ret < 0) return ret; - switch (value) { - case AB8500_CUT1P0: - case AB8500_CUT1P1: - case AB8500_CUT2P0: - case AB8500_CUT3P0: - case AB8500_CUT3P3: - dev_info(ab8500->dev, "detected chip, revision: %#x\n", value); - break; - default: - dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value); - return -EINVAL; - } ab8500->chip_id = value; + dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n", + ab8500_version_str[ab8500->version], + ab8500->chip_id >> 4, + ab8500->chip_id & 0x0F); + /* * ab8500 has switched off due to (SWITCH_OFF_STATUS): * 0x01 Swoff bit programming @@ -922,9 +940,12 @@ int __devinit ab8500_init(struct ab8500 *ab8500) /* Clear and mask all interrupts */ for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) { - /* Interrupt register 12 doesn't exist prior to version 2.0 */ - if (ab8500_irq_regoffset[i] == 11 && - ab8500->chip_id < AB8500_CUT2P0) + /* + * Interrupt register 12 doesn't exist prior to AB8500 version + * 2.0 + */ + if (ab8500->irq_reg_offset[i] == 11 && + is_ab8500_1p1_or_earlier(ab8500)) continue; get_register_interruptible(ab8500, AB8500_INTERRUPT, diff --git a/drivers/mfd/ab8500-i2c.c b/drivers/mfd/ab8500-i2c.c index e05836723ac..1c0d1fbdb2a 100644 --- a/drivers/mfd/ab8500-i2c.c +++ b/drivers/mfd/ab8500-i2c.c @@ -39,6 +39,7 @@ static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr) static int __devinit ab8500_i2c_probe(struct platform_device *plf) { + const struct platform_device_id *platid = platform_get_device_id(plf); struct ab8500 *ab8500; struct resource *resource; int ret; @@ -62,10 +63,11 @@ static int __devinit ab8500_i2c_probe(struct platform_device *plf) platform_set_drvdata(plf, ab8500); - ret = ab8500_init(ab8500); + ret = ab8500_init(ab8500, platid->driver_data); if (ret) kfree(ab8500); + return ret; } @@ -79,13 +81,22 @@ static int __devexit ab8500_i2c_remove(struct platform_device *plf) return 0; } +static const struct platform_device_id ab8500_id[] = { + { "ab8500-i2c", AB8500_VERSION_AB8500 }, + { "ab8505-i2c", AB8500_VERSION_AB8505 }, + { "ab9540-i2c", AB8500_VERSION_AB9540 }, + { "ab8540-i2c", AB8500_VERSION_AB8540 }, + { } +}; + static struct platform_driver ab8500_i2c_driver = { .driver = { .name = "ab8500-i2c", .owner = THIS_MODULE, }, .probe = ab8500_i2c_probe, - .remove = __devexit_p(ab8500_i2c_remove) + .remove = __devexit_p(ab8500_i2c_remove), + .id_table = ab8500_id, }; static int __init ab8500_i2c_init(void) |