diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2012-02-20 15:42:10 -0500 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2012-03-06 12:46:42 -0500 |
commit | 0f620837595145cd42be1c9dc6b619146fbeaf88 (patch) | |
tree | c8baef44fa4b407ef897ccd234b91f8d83ac85e3 /drivers/mfd/ab8500-core.c | |
parent | 6d95b7fdd0bd2e28ef651da6863d75edca4c2aca (diff) |
mfd: Add ab8500 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.
Reviewed-by: 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>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd/ab8500-core.c')
-rw-r--r-- | drivers/mfd/ab8500-core.c | 63 |
1 files changed, 42 insertions, 21 deletions
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index d295941c9a3d..3547eee21aa4 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c | |||
@@ -90,6 +90,7 @@ | |||
90 | #define AB8500_IT_MASK24_REG 0x57 | 90 | #define AB8500_IT_MASK24_REG 0x57 |
91 | 91 | ||
92 | #define AB8500_REV_REG 0x80 | 92 | #define AB8500_REV_REG 0x80 |
93 | #define AB8500_IC_NAME_REG 0x82 | ||
93 | #define AB8500_SWITCH_OFF_STATUS 0x00 | 94 | #define AB8500_SWITCH_OFF_STATUS 0x00 |
94 | 95 | ||
95 | #define AB8500_TURN_ON_STATUS 0x00 | 96 | #define AB8500_TURN_ON_STATUS 0x00 |
@@ -105,6 +106,13 @@ static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = { | |||
105 | 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, | 106 | 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, |
106 | }; | 107 | }; |
107 | 108 | ||
109 | static const char ab8500_version_str[][7] = { | ||
110 | [AB8500_VERSION_AB8500] = "AB8500", | ||
111 | [AB8500_VERSION_AB8505] = "AB8505", | ||
112 | [AB8500_VERSION_AB9540] = "AB9540", | ||
113 | [AB8500_VERSION_AB8540] = "AB8540", | ||
114 | }; | ||
115 | |||
108 | static int ab8500_get_chip_id(struct device *dev) | 116 | static int ab8500_get_chip_id(struct device *dev) |
109 | { | 117 | { |
110 | struct ab8500 *ab8500; | 118 | struct ab8500 *ab8500; |
@@ -256,9 +264,12 @@ static void ab8500_irq_sync_unlock(struct irq_data *data) | |||
256 | if (new == old) | 264 | if (new == old) |
257 | continue; | 265 | continue; |
258 | 266 | ||
259 | /* Interrupt register 12 doesn't exist prior to version 2.0 */ | 267 | /* |
260 | if (ab8500_irq_regoffset[i] == 11 && | 268 | * Interrupt register 12 doesn't exist prior to AB8500 version |
261 | ab8500->chip_id < AB8500_CUT2P0) | 269 | * 2.0 |
270 | */ | ||
271 | if (ab8500->irq_reg_offset[i] == 11 && | ||
272 | is_ab8500_1p1_or_earlier(ab8500)) | ||
262 | continue; | 273 | continue; |
263 | 274 | ||
264 | ab8500->oldmask[i] = new; | 275 | ab8500->oldmask[i] = new; |
@@ -311,8 +322,11 @@ static irqreturn_t ab8500_irq(int irq, void *dev) | |||
311 | int status; | 322 | int status; |
312 | u8 value; | 323 | u8 value; |
313 | 324 | ||
314 | /* Interrupt register 12 doesn't exist prior to version 2.0 */ | 325 | /* |
315 | if (regoffset == 11 && ab8500->chip_id < AB8500_CUT2P0) | 326 | * Interrupt register 12 doesn't exist prior to AB8500 version |
327 | * 2.0 | ||
328 | */ | ||
329 | if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500)) | ||
316 | continue; | 330 | continue; |
317 | 331 | ||
318 | status = get_register_interruptible(ab8500, AB8500_INTERRUPT, | 332 | status = get_register_interruptible(ab8500, AB8500_INTERRUPT, |
@@ -857,7 +871,7 @@ static struct attribute_group ab8500_attr_group = { | |||
857 | .attrs = ab8500_sysfs_entries, | 871 | .attrs = ab8500_sysfs_entries, |
858 | }; | 872 | }; |
859 | 873 | ||
860 | int __devinit ab8500_init(struct ab8500 *ab8500) | 874 | int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version) |
861 | { | 875 | { |
862 | struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev); | 876 | struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev); |
863 | int ret; | 877 | int ret; |
@@ -870,25 +884,29 @@ int __devinit ab8500_init(struct ab8500 *ab8500) | |||
870 | mutex_init(&ab8500->lock); | 884 | mutex_init(&ab8500->lock); |
871 | mutex_init(&ab8500->irq_lock); | 885 | mutex_init(&ab8500->irq_lock); |
872 | 886 | ||
887 | if (version != AB8500_VERSION_UNDEFINED) | ||
888 | ab8500->version = version; | ||
889 | else { | ||
890 | ret = get_register_interruptible(ab8500, AB8500_MISC, | ||
891 | AB8500_IC_NAME_REG, &value); | ||
892 | if (ret < 0) | ||
893 | return ret; | ||
894 | |||
895 | ab8500->version = value; | ||
896 | } | ||
897 | |||
873 | ret = get_register_interruptible(ab8500, AB8500_MISC, | 898 | ret = get_register_interruptible(ab8500, AB8500_MISC, |
874 | AB8500_REV_REG, &value); | 899 | AB8500_REV_REG, &value); |
875 | if (ret < 0) | 900 | if (ret < 0) |
876 | return ret; | 901 | return ret; |
877 | 902 | ||
878 | switch (value) { | ||
879 | case AB8500_CUT1P0: | ||
880 | case AB8500_CUT1P1: | ||
881 | case AB8500_CUT2P0: | ||
882 | case AB8500_CUT3P0: | ||
883 | case AB8500_CUT3P3: | ||
884 | dev_info(ab8500->dev, "detected chip, revision: %#x\n", value); | ||
885 | break; | ||
886 | default: | ||
887 | dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value); | ||
888 | return -EINVAL; | ||
889 | } | ||
890 | ab8500->chip_id = value; | 903 | ab8500->chip_id = value; |
891 | 904 | ||
905 | dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n", | ||
906 | ab8500_version_str[ab8500->version], | ||
907 | ab8500->chip_id >> 4, | ||
908 | ab8500->chip_id & 0x0F); | ||
909 | |||
892 | /* | 910 | /* |
893 | * ab8500 has switched off due to (SWITCH_OFF_STATUS): | 911 | * ab8500 has switched off due to (SWITCH_OFF_STATUS): |
894 | * 0x01 Swoff bit programming | 912 | * 0x01 Swoff bit programming |
@@ -912,9 +930,12 @@ int __devinit ab8500_init(struct ab8500 *ab8500) | |||
912 | 930 | ||
913 | /* Clear and mask all interrupts */ | 931 | /* Clear and mask all interrupts */ |
914 | for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) { | 932 | for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) { |
915 | /* Interrupt register 12 doesn't exist prior to version 2.0 */ | 933 | /* |
916 | if (ab8500_irq_regoffset[i] == 11 && | 934 | * Interrupt register 12 doesn't exist prior to AB8500 version |
917 | ab8500->chip_id < AB8500_CUT2P0) | 935 | * 2.0 |
936 | */ | ||
937 | if (ab8500->irq_reg_offset[i] == 11 && | ||
938 | is_ab8500_1p1_or_earlier(ab8500)) | ||
918 | continue; | 939 | continue; |
919 | 940 | ||
920 | get_register_interruptible(ab8500, AB8500_INTERRUPT, | 941 | get_register_interruptible(ab8500, AB8500_INTERRUPT, |