diff options
author | Balaji T K <balajitk@ti.com> | 2009-12-13 18:25:31 -0500 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2009-12-13 18:25:31 -0500 |
commit | e8deb28ca8e221de0239eafb3c3d431d8854278e (patch) | |
tree | 2dffdb207366aa0a8f229775515fc207c16f8574 /drivers/mfd/twl-core.c | |
parent | c4aa6f314328142974c78377cd9476f8ec6f0eba (diff) |
mfd: Add support for twl6030 irq framework
This patch adds support for phoenix interrupt framework. New iInterrupt
status register A, B, C are introduced in Phoenix and are cleared on write.
Due to the differences in interrupt handling with respect to TWL4030,
twl6030-irq.c is created for TWL6030 PMIC
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
Signed-off-by: Balaji T K <balajitk@ti.com>
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Reviewed-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd/twl-core.c')
-rw-r--r-- | drivers/mfd/twl-core.c | 120 |
1 files changed, 106 insertions, 14 deletions
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 79946fe800af..c48a6138c575 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c | |||
@@ -181,6 +181,30 @@ | |||
181 | /* Triton Core internal information (END) */ | 181 | /* Triton Core internal information (END) */ |
182 | 182 | ||
183 | 183 | ||
184 | /* subchip/slave 0 0x48 - POWER */ | ||
185 | #define TWL6030_BASEADD_RTC 0x0000 | ||
186 | #define TWL6030_BASEADD_MEM 0x0017 | ||
187 | #define TWL6030_BASEADD_PM_MASTER 0x001F | ||
188 | #define TWL6030_BASEADD_PM_SLAVE_MISC 0x0030 /* PM_RECEIVER */ | ||
189 | #define TWL6030_BASEADD_PM_MISC 0x00E2 | ||
190 | #define TWL6030_BASEADD_PM_PUPD 0x00F0 | ||
191 | |||
192 | /* subchip/slave 1 0x49 - FEATURE */ | ||
193 | #define TWL6030_BASEADD_USB 0x0000 | ||
194 | #define TWL6030_BASEADD_GPADC_CTRL 0x002E | ||
195 | #define TWL6030_BASEADD_AUX 0x0090 | ||
196 | #define TWL6030_BASEADD_PWM 0x00BA | ||
197 | #define TWL6030_BASEADD_GASGAUGE 0x00C0 | ||
198 | #define TWL6030_BASEADD_PIH 0x00D0 | ||
199 | #define TWL6030_BASEADD_CHARGER 0x00E0 | ||
200 | |||
201 | /* subchip/slave 2 0x4A - DFT */ | ||
202 | #define TWL6030_BASEADD_DIEID 0x00C0 | ||
203 | |||
204 | /* subchip/slave 3 0x4B - AUDIO */ | ||
205 | #define TWL6030_BASEADD_AUDIO 0x0000 | ||
206 | #define TWL6030_BASEADD_RSV 0x0000 | ||
207 | |||
184 | /* Few power values */ | 208 | /* Few power values */ |
185 | #define R_CFG_BOOT 0x05 | 209 | #define R_CFG_BOOT 0x05 |
186 | #define R_PROTECT_KEY 0x0E | 210 | #define R_PROTECT_KEY 0x0E |
@@ -202,13 +226,21 @@ | |||
202 | #define TWL4030_VAUX2 BIT(0) /* pre-5030 voltage ranges */ | 226 | #define TWL4030_VAUX2 BIT(0) /* pre-5030 voltage ranges */ |
203 | #define TPS_SUBSET BIT(1) /* tps659[23]0 have fewer LDOs */ | 227 | #define TPS_SUBSET BIT(1) /* tps659[23]0 have fewer LDOs */ |
204 | #define TWL5031 BIT(2) /* twl5031 has different registers */ | 228 | #define TWL5031 BIT(2) /* twl5031 has different registers */ |
229 | #define TWL6030_CLASS BIT(3) /* TWL6030 class */ | ||
205 | 230 | ||
206 | /*----------------------------------------------------------------------*/ | 231 | /*----------------------------------------------------------------------*/ |
207 | 232 | ||
208 | /* is driver active, bound to a chip? */ | 233 | /* is driver active, bound to a chip? */ |
209 | static bool inuse; | 234 | static bool inuse; |
210 | 235 | ||
211 | /* Structure for each TWL4030 Slave */ | 236 | static unsigned int twl_id; |
237 | unsigned int twl_rev(void) | ||
238 | { | ||
239 | return twl_id; | ||
240 | } | ||
241 | EXPORT_SYMBOL(twl_rev); | ||
242 | |||
243 | /* Structure for each TWL4030/TWL6030 Slave */ | ||
212 | struct twl_client { | 244 | struct twl_client { |
213 | struct i2c_client *client; | 245 | struct i2c_client *client; |
214 | u8 address; | 246 | u8 address; |
@@ -228,11 +260,12 @@ struct twl_mapping { | |||
228 | unsigned char sid; /* Slave ID */ | 260 | unsigned char sid; /* Slave ID */ |
229 | unsigned char base; /* base address */ | 261 | unsigned char base; /* base address */ |
230 | }; | 262 | }; |
263 | struct twl_mapping *twl_map; | ||
231 | 264 | ||
232 | static struct twl_mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { | 265 | static struct twl_mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { |
233 | /* | 266 | /* |
234 | * NOTE: don't change this table without updating the | 267 | * NOTE: don't change this table without updating the |
235 | * <linux/i2c/twl4030.h> defines for TWL4030_MODULE_* | 268 | * <linux/i2c/twl.h> defines for TWL4030_MODULE_* |
236 | * so they continue to match the order in this table. | 269 | * so they continue to match the order in this table. |
237 | */ | 270 | */ |
238 | 271 | ||
@@ -265,6 +298,40 @@ static struct twl_mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { | |||
265 | { 3, TWL4030_BASEADD_SECURED_REG }, | 298 | { 3, TWL4030_BASEADD_SECURED_REG }, |
266 | }; | 299 | }; |
267 | 300 | ||
301 | static struct twl_mapping twl6030_map[] = { | ||
302 | /* | ||
303 | * NOTE: don't change this table without updating the | ||
304 | * <linux/i2c/twl.h> defines for TWL4030_MODULE_* | ||
305 | * so they continue to match the order in this table. | ||
306 | */ | ||
307 | { SUB_CHIP_ID1, TWL6030_BASEADD_USB }, | ||
308 | { SUB_CHIP_ID3, TWL6030_BASEADD_AUDIO }, | ||
309 | { SUB_CHIP_ID2, TWL6030_BASEADD_DIEID }, | ||
310 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
311 | { SUB_CHIP_ID1, TWL6030_BASEADD_PIH }, | ||
312 | |||
313 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
314 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
315 | { SUB_CHIP_ID1, TWL6030_BASEADD_GPADC_CTRL }, | ||
316 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
317 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
318 | |||
319 | { SUB_CHIP_ID1, TWL6030_BASEADD_CHARGER }, | ||
320 | { SUB_CHIP_ID1, TWL6030_BASEADD_GASGAUGE }, | ||
321 | { SUB_CHIP_ID1, TWL6030_BASEADD_PWM }, | ||
322 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
323 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
324 | |||
325 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
326 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
327 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
328 | { SUB_CHIP_ID0, TWL6030_BASEADD_PM_MASTER }, | ||
329 | { SUB_CHIP_ID0, TWL6030_BASEADD_PM_SLAVE_MISC }, | ||
330 | |||
331 | { SUB_CHIP_ID0, TWL6030_BASEADD_RTC }, | ||
332 | { SUB_CHIP_ID0, TWL6030_BASEADD_MEM }, | ||
333 | }; | ||
334 | |||
268 | /*----------------------------------------------------------------------*/ | 335 | /*----------------------------------------------------------------------*/ |
269 | 336 | ||
270 | /* Exported Functions */ | 337 | /* Exported Functions */ |
@@ -292,7 +359,7 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) | |||
292 | pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); | 359 | pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); |
293 | return -EPERM; | 360 | return -EPERM; |
294 | } | 361 | } |
295 | sid = twl4030_map[mod_no].sid; | 362 | sid = twl_map[mod_no].sid; |
296 | twl = &twl_modules[sid]; | 363 | twl = &twl_modules[sid]; |
297 | 364 | ||
298 | if (unlikely(!inuse)) { | 365 | if (unlikely(!inuse)) { |
@@ -310,7 +377,7 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) | |||
310 | msg->flags = 0; | 377 | msg->flags = 0; |
311 | msg->buf = value; | 378 | msg->buf = value; |
312 | /* over write the first byte of buffer with the register address */ | 379 | /* over write the first byte of buffer with the register address */ |
313 | *value = twl4030_map[mod_no].base + reg; | 380 | *value = twl_map[mod_no].base + reg; |
314 | ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 1); | 381 | ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 1); |
315 | mutex_unlock(&twl->xfer_lock); | 382 | mutex_unlock(&twl->xfer_lock); |
316 | 383 | ||
@@ -349,7 +416,7 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) | |||
349 | pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); | 416 | pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); |
350 | return -EPERM; | 417 | return -EPERM; |
351 | } | 418 | } |
352 | sid = twl4030_map[mod_no].sid; | 419 | sid = twl_map[mod_no].sid; |
353 | twl = &twl_modules[sid]; | 420 | twl = &twl_modules[sid]; |
354 | 421 | ||
355 | if (unlikely(!inuse)) { | 422 | if (unlikely(!inuse)) { |
@@ -362,7 +429,7 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) | |||
362 | msg->addr = twl->address; | 429 | msg->addr = twl->address; |
363 | msg->len = 1; | 430 | msg->len = 1; |
364 | msg->flags = 0; /* Read the register value */ | 431 | msg->flags = 0; /* Read the register value */ |
365 | val = twl4030_map[mod_no].base + reg; | 432 | val = twl_map[mod_no].base + reg; |
366 | msg->buf = &val; | 433 | msg->buf = &val; |
367 | /* [MSG2] fill the data rx buffer */ | 434 | /* [MSG2] fill the data rx buffer */ |
368 | msg = &twl->xfer_msg[1]; | 435 | msg = &twl->xfer_msg[1]; |
@@ -486,6 +553,7 @@ add_regulator_linked(int num, struct regulator_init_data *pdata, | |||
486 | struct regulator_consumer_supply *consumers, | 553 | struct regulator_consumer_supply *consumers, |
487 | unsigned num_consumers) | 554 | unsigned num_consumers) |
488 | { | 555 | { |
556 | unsigned sub_chip_id; | ||
489 | /* regulator framework demands init_data ... */ | 557 | /* regulator framework demands init_data ... */ |
490 | if (!pdata) | 558 | if (!pdata) |
491 | return NULL; | 559 | return NULL; |
@@ -496,7 +564,8 @@ add_regulator_linked(int num, struct regulator_init_data *pdata, | |||
496 | } | 564 | } |
497 | 565 | ||
498 | /* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */ | 566 | /* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */ |
499 | return add_numbered_child(3, "twl_reg", num, | 567 | sub_chip_id = twl_map[TWL_MODULE_PM_MASTER].sid; |
568 | return add_numbered_child(sub_chip_id, "twl_reg", num, | ||
500 | pdata, sizeof(*pdata), false, 0, 0); | 569 | pdata, sizeof(*pdata), false, 0, 0); |
501 | } | 570 | } |
502 | 571 | ||
@@ -516,6 +585,7 @@ static int | |||
516 | add_children(struct twl4030_platform_data *pdata, unsigned long features) | 585 | add_children(struct twl4030_platform_data *pdata, unsigned long features) |
517 | { | 586 | { |
518 | struct device *child; | 587 | struct device *child; |
588 | unsigned sub_chip_id; | ||
519 | 589 | ||
520 | if (twl_has_bci() && pdata->bci && | 590 | if (twl_has_bci() && pdata->bci && |
521 | !(features & (TPS_SUBSET | TWL5031))) { | 591 | !(features & (TPS_SUBSET | TWL5031))) { |
@@ -561,7 +631,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
561 | * Eventually, Linux might become more aware of such | 631 | * Eventually, Linux might become more aware of such |
562 | * HW security concerns, and "least privilege". | 632 | * HW security concerns, and "least privilege". |
563 | */ | 633 | */ |
564 | child = add_child(3, "twl_rtc", | 634 | sub_chip_id = twl_map[TWL_MODULE_RTC].sid; |
635 | child = add_child(sub_chip_id, "twl_rtc", | ||
565 | NULL, 0, | 636 | NULL, 0, |
566 | true, pdata->irq_base + RTC_INTR_OFFSET, 0); | 637 | true, pdata->irq_base + RTC_INTR_OFFSET, 0); |
567 | if (IS_ERR(child)) | 638 | if (IS_ERR(child)) |
@@ -812,16 +883,22 @@ static void clocks_init(struct device *dev, | |||
812 | 883 | ||
813 | /*----------------------------------------------------------------------*/ | 884 | /*----------------------------------------------------------------------*/ |
814 | 885 | ||
815 | int twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end); | 886 | int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end); |
816 | int twl_exit_irq(void); | 887 | int twl4030_exit_irq(void); |
817 | int twl_init_chip_irq(const char *chip); | 888 | int twl4030_init_chip_irq(const char *chip); |
889 | int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end); | ||
890 | int twl6030_exit_irq(void); | ||
818 | 891 | ||
819 | static int twl_remove(struct i2c_client *client) | 892 | static int twl_remove(struct i2c_client *client) |
820 | { | 893 | { |
821 | unsigned i; | 894 | unsigned i; |
822 | int status; | 895 | int status; |
823 | 896 | ||
824 | status = twl_exit_irq(); | 897 | if (twl_class_is_4030()) |
898 | status = twl4030_exit_irq(); | ||
899 | else | ||
900 | status = twl6030_exit_irq(); | ||
901 | |||
825 | if (status < 0) | 902 | if (status < 0) |
826 | return status; | 903 | return status; |
827 | 904 | ||
@@ -878,6 +955,13 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
878 | mutex_init(&twl->xfer_lock); | 955 | mutex_init(&twl->xfer_lock); |
879 | } | 956 | } |
880 | inuse = true; | 957 | inuse = true; |
958 | if ((id->driver_data) & TWL6030_CLASS) { | ||
959 | twl_id = TWL6030_CLASS_ID; | ||
960 | twl_map = &twl6030_map[0]; | ||
961 | } else { | ||
962 | twl_id = TWL4030_CLASS_ID; | ||
963 | twl_map = &twl4030_map[0]; | ||
964 | } | ||
881 | 965 | ||
882 | /* setup clock framework */ | 966 | /* setup clock framework */ |
883 | clocks_init(&client->dev, pdata->clock); | 967 | clocks_init(&client->dev, pdata->clock); |
@@ -890,8 +974,15 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
890 | if (client->irq | 974 | if (client->irq |
891 | && pdata->irq_base | 975 | && pdata->irq_base |
892 | && pdata->irq_end > pdata->irq_base) { | 976 | && pdata->irq_end > pdata->irq_base) { |
893 | twl_init_chip_irq(id->name); | 977 | if (twl_class_is_4030()) { |
894 | status = twl_init_irq(client->irq, pdata->irq_base, pdata->irq_end); | 978 | twl4030_init_chip_irq(id->name); |
979 | status = twl4030_init_irq(client->irq, pdata->irq_base, | ||
980 | pdata->irq_end); | ||
981 | } else { | ||
982 | status = twl6030_init_irq(client->irq, pdata->irq_base, | ||
983 | pdata->irq_end); | ||
984 | } | ||
985 | |||
895 | if (status < 0) | 986 | if (status < 0) |
896 | goto fail; | 987 | goto fail; |
897 | } | 988 | } |
@@ -910,6 +1001,7 @@ static const struct i2c_device_id twl_ids[] = { | |||
910 | { "tps65950", 0 }, /* catalog version of twl5030 */ | 1001 | { "tps65950", 0 }, /* catalog version of twl5030 */ |
911 | { "tps65930", TPS_SUBSET }, /* fewer LDOs and DACs; no charger */ | 1002 | { "tps65930", TPS_SUBSET }, /* fewer LDOs and DACs; no charger */ |
912 | { "tps65920", TPS_SUBSET }, /* fewer LDOs; no codec or charger */ | 1003 | { "tps65920", TPS_SUBSET }, /* fewer LDOs; no codec or charger */ |
1004 | { "twl6030", TWL6030_CLASS }, /* "Phoenix power chip" */ | ||
913 | { /* end of list */ }, | 1005 | { /* end of list */ }, |
914 | }; | 1006 | }; |
915 | MODULE_DEVICE_TABLE(i2c, twl_ids); | 1007 | MODULE_DEVICE_TABLE(i2c, twl_ids); |