From f04a9d8adf766c480353c0f2427e641251c9b059 Mon Sep 17 00:00:00 2001 From: Rajkumar Kasirajan Date: Wed, 30 May 2012 16:32:37 +0530 Subject: mfd: ab8500-sysctrl: Update correct turn on status In L9540, turn_on_status register is not updated correctly if the device is rebooted with AC/USB charger connected. Due to this, the device boots android instead of entering into charge only mode. Read the AC/USB status register to detect the charger presence and update the turn on status manually. Signed-off-by: Rajkumar Kasirajan Signed-off-by: Per Forlin Signed-off-by: Lee Jones Reviewed-by: Rupesh KUMAR Reviewed-by: Philippe LANGLAIS Tested-by: Rupesh KUMAR Tested-by: Philippe LANGLAIS Acked-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'drivers/mfd/ab8500-core.c') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 7c84ced2e01b..50e6f1e29727 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -111,6 +111,13 @@ #define AB8500_TURN_ON_STATUS 0x00 +#define AB8500_CH_USBCH_STAT1_REG 0x02 +#define VBUS_DET_DBNC100 0x02 +#define VBUS_DET_DBNC1 0x01 + +static DEFINE_SPINLOCK(on_stat_lock); +static u8 turn_on_stat_mask = 0xFF; +static u8 turn_on_stat_set; static bool no_bm; /* No battery management */ module_param(no_bm, bool, S_IRUGO); @@ -1171,6 +1178,15 @@ static ssize_t show_switch_off_status(struct device *dev, return sprintf(buf, "%#x\n", value); } +/* use mask and set to override the register turn_on_stat value */ +void ab8500_override_turn_on_stat(u8 mask, u8 set) +{ + spin_lock(&on_stat_lock); + turn_on_stat_mask = mask; + turn_on_stat_set = set; + spin_unlock(&on_stat_lock); +} + /* * ab8500 has turned on due to (TURN_ON_STATUS): * 0x01 PORnVbat @@ -1194,6 +1210,20 @@ static ssize_t show_turn_on_status(struct device *dev, AB8500_TURN_ON_STATUS, &value); if (ret < 0) return ret; + + /* + * In L9540, turn_on_status register is not updated correctly if + * the device is rebooted with AC/USB charger connected. Due to + * this, the device boots android instead of entering into charge + * only mode. Read the AC/USB status register to detect the charger + * presence and update the turn on status manually. + */ + if (is_ab9540(ab8500)) { + spin_lock(&on_stat_lock); + value = (value & turn_on_stat_mask) | turn_on_stat_set; + spin_unlock(&on_stat_lock); + } + return sprintf(buf, "%#x\n", value); } @@ -1399,6 +1429,15 @@ static int ab8500_probe(struct platform_device *pdev) if (plat && plat->init) plat->init(ab8500); + if (is_ab9540(ab8500)) { + ret = get_register_interruptible(ab8500, AB8500_CHARGER, + AB8500_CH_USBCH_STAT1_REG, &value); + if (ret < 0) + return ret; + if ((value & VBUS_DET_DBNC1) && (value & VBUS_DET_DBNC100)) + ab8500_override_turn_on_stat(~AB8500_POW_KEY_1_ON, + AB8500_VBUS_DET); + } /* Clear and mask all interrupts */ for (i = 0; i < ab8500->mask_size; i++) { -- cgit v1.2.3 From a29264b68a93556a09005b9f18cbd3f61f6fd355 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 25 Feb 2013 14:34:26 +0000 Subject: mfd: ab8500-core: APE Interrupts are not cleared There are missing register descriptions from the AB8505 user manual and these need to be masked so that the APEINT line can toggle. This patch also affects the behaviour of AB9540. Signed-off-by: Marcus Cooper Signed-off-by: Lee Jones Reviewed-by: Maxime COQUELIN Reviewed-by: Alexandre TORGUE Reviewed-by: Mattias WALLIN Acked-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/mfd/ab8500-core.c') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 50e6f1e29727..baaf2ed8095b 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -95,6 +95,7 @@ #define AB8500_IT_MASK22_REG 0x55 #define AB8500_IT_MASK23_REG 0x56 #define AB8500_IT_MASK24_REG 0x57 +#define AB8500_IT_MASK25_REG 0x58 /* * latch hierarchy registers @@ -137,9 +138,9 @@ static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = { 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, }; -/* AB9540 support */ +/* AB9540 / AB8505 support */ static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = { - 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24, + 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 23 }; static const char ab8500_version_str[][7] = { -- cgit v1.2.3 From c0eda9aef1c0ef7bb2812b739ddf400405568bef Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 12 Feb 2013 15:04:09 +0000 Subject: mfd: ab8500-core: Add ADC support for ab8540 Signed-off-by: Lee Jones Acked-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 74 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 15 deletions(-) (limited to 'drivers/mfd/ab8500-core.c') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index baaf2ed8095b..cdf6c1e59bc3 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -658,6 +658,15 @@ static struct resource ab8500_gpadc_resources[] = { }, }; +static struct resource ab8540_gpadc_resources[] = { + { + .name = "SW_CONV_END", + .start = AB8500_INT_GP_SW_ADC_CONV_END, + .end = AB8500_INT_GP_SW_ADC_CONV_END, + .flags = IORESOURCE_IRQ, + }, +}; + static struct resource ab8500_rtc_resources[] = { { .name = "60S", @@ -1013,12 +1022,6 @@ static struct mfd_cell abx500_common_devs[] = { .name = "abx500-clk", .of_compatible = "stericsson,abx500-clk", }, - { - .name = "ab8500-gpadc", - .of_compatible = "stericsson,ab8500-gpadc", - .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), - .resources = ab8500_gpadc_resources, - }, { .name = "ab8500-rtc", .of_compatible = "stericsson,ab8500-rtc", @@ -1118,6 +1121,12 @@ static struct mfd_cell ab8500_devs[] = { .name = "ab8500-codec", .of_compatible = "stericsson,ab8500-codec", }, + { + .name = "ab8500-gpadc", + .of_compatible = "stericsson,ab8500-gpadc", + .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), + .resources = ab8500_gpadc_resources, + }, }; static struct mfd_cell ab9540_devs[] = { @@ -1133,10 +1142,44 @@ static struct mfd_cell ab9540_devs[] = { { .name = "ab9540-codec", }, + { + .name = "ab8500-gpadc", + .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), + .resources = ab8500_gpadc_resources, + }, + { + .name = "ab-iddet", + .num_resources = ARRAY_SIZE(ab8505_iddet_resources), + .resources = ab8505_iddet_resources, + }, }; -/* Device list common to ab9540 and ab8505 */ -static struct mfd_cell ab9540_ab8505_devs[] = { +/* Device list for ab8505 */ +static struct mfd_cell ab8505_devs[] = { + { + .name = "ab-iddet", + .num_resources = ARRAY_SIZE(ab8505_iddet_resources), + .resources = ab8505_iddet_resources, + }, +}; + +static struct mfd_cell ab8540_devs[] = { + { + .name = "ab8500-gpio", + }, + { + .name = "ab8540-usb", + .num_resources = ARRAY_SIZE(ab8500_usb_resources), + .resources = ab8500_usb_resources, + }, + { + .name = "ab8540-codec", + }, + { + .name = "ab8500-gpadc", + .num_resources = ARRAY_SIZE(ab8540_gpadc_resources), + .resources = ab8540_gpadc_resources, + }, { .name = "ab-iddet", .num_resources = ARRAY_SIZE(ab8505_iddet_resources), @@ -1495,6 +1538,14 @@ static int ab8500_probe(struct platform_device *pdev) ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, ARRAY_SIZE(ab9540_devs), NULL, ab8500->irq_base, ab8500->domain); + else if (is_ab8540(ab8500)) + ret = mfd_add_devices(ab8500->dev, 0, ab8540_devs, + ARRAY_SIZE(ab8540_devs), NULL, + ab8500->irq_base, ab8500->domain); + else if (is_ab8505(ab8500)) + ret = mfd_add_devices(ab8500->dev, 0, ab8505_devs, + ARRAY_SIZE(ab8505_devs), NULL, + ab8500->irq_base, ab8500->domain); else ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs, ARRAY_SIZE(ab8500_devs), NULL, @@ -1502,13 +1553,6 @@ static int ab8500_probe(struct platform_device *pdev) if (ret) return ret; - if (is_ab9540(ab8500) || is_ab8505(ab8500)) - ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs, - ARRAY_SIZE(ab9540_ab8505_devs), NULL, - ab8500->irq_base, ab8500->domain); - if (ret) - return ret; - if (!no_bm) { /* Add battery management devices */ ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, -- cgit v1.2.3 From 4b106fb9895c7edba2acd41c152e8f6edf724651 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 25 Feb 2013 14:42:00 +0000 Subject: mfd: ab8500-core: Rework MFD sub-device initialisation structures Here we're separating Battery Management devices into their own structure, removing the common device structure & redistribute them amongst the individual platform structs and completing the population of them. Signed-off-by: Lee Jones Acked-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 243 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 182 insertions(+), 61 deletions(-) (limited to 'drivers/mfd/ab8500-core.c') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index cdf6c1e59bc3..23db4fcea496 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -658,7 +658,7 @@ static struct resource ab8500_gpadc_resources[] = { }, }; -static struct resource ab8540_gpadc_resources[] = { +static struct resource ab8505_gpadc_resources[] = { { .name = "SW_CONV_END", .start = AB8500_INT_GP_SW_ADC_CONV_END, @@ -1001,7 +1001,42 @@ static struct resource ab8500_temp_resources[] = { }, }; -static struct mfd_cell abx500_common_devs[] = { +static struct mfd_cell ab8500_bm_devs[] = { + { + .name = "ab8500-charger", + .of_compatible = "stericsson,ab8500-charger", + .num_resources = ARRAY_SIZE(ab8500_charger_resources), + .resources = ab8500_charger_resources, + .platform_data = &ab8500_bm_data, + .pdata_size = sizeof(ab8500_bm_data), + }, + { + .name = "ab8500-btemp", + .of_compatible = "stericsson,ab8500-btemp", + .num_resources = ARRAY_SIZE(ab8500_btemp_resources), + .resources = ab8500_btemp_resources, + .platform_data = &ab8500_bm_data, + .pdata_size = sizeof(ab8500_bm_data), + }, + { + .name = "ab8500-fg", + .of_compatible = "stericsson,ab8500-fg", + .num_resources = ARRAY_SIZE(ab8500_fg_resources), + .resources = ab8500_fg_resources, + .platform_data = &ab8500_bm_data, + .pdata_size = sizeof(ab8500_bm_data), + }, + { + .name = "ab8500-chargalg", + .of_compatible = "stericsson,ab8500-chargalg", + .num_resources = ARRAY_SIZE(ab8500_chargalg_resources), + .resources = ab8500_chargalg_resources, + .platform_data = &ab8500_bm_data, + .pdata_size = sizeof(ab8500_bm_data), + }, +}; + +static struct mfd_cell ab8500_devs[] = { #ifdef CONFIG_DEBUG_FS { .name = "ab8500-debug", @@ -1022,6 +1057,11 @@ static struct mfd_cell abx500_common_devs[] = { .name = "abx500-clk", .of_compatible = "stericsson,abx500-clk", }, + { + .name = "ab8500-gpadc", + .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), + .resources = ab8500_gpadc_resources, + }, { .name = "ab8500-rtc", .of_compatible = "stericsson,ab8500-rtc", @@ -1035,6 +1075,7 @@ static struct mfd_cell abx500_common_devs[] = { .resources = ab8500_av_acc_detect_resources, }, { + .name = "ab8500-poweron-key", .of_compatible = "stericsson,ab8500-poweron-key", .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources), @@ -1063,63 +1104,39 @@ static struct mfd_cell abx500_common_devs[] = { .name = "ab8500-denc", .of_compatible = "stericsson,ab8500-denc", }, + { + .name = "ab8500-gpio", + .of_compatible = "stericsson,ab8500-gpio", + }, { .name = "abx500-temp", .of_compatible = "stericsson,abx500-temp", .num_resources = ARRAY_SIZE(ab8500_temp_resources), .resources = ab8500_temp_resources, }, -}; - -static struct mfd_cell ab8500_bm_devs[] = { - { - .name = "ab8500-charger", - .of_compatible = "stericsson,ab8500-charger", - .num_resources = ARRAY_SIZE(ab8500_charger_resources), - .resources = ab8500_charger_resources, - .platform_data = &ab8500_bm_data, - .pdata_size = sizeof(ab8500_bm_data), - }, { - .name = "ab8500-btemp", - .of_compatible = "stericsson,ab8500-btemp", - .num_resources = ARRAY_SIZE(ab8500_btemp_resources), - .resources = ab8500_btemp_resources, - .platform_data = &ab8500_bm_data, - .pdata_size = sizeof(ab8500_bm_data), - }, - { - .name = "ab8500-fg", - .of_compatible = "stericsson,ab8500-fg", - .num_resources = ARRAY_SIZE(ab8500_fg_resources), - .resources = ab8500_fg_resources, - .platform_data = &ab8500_bm_data, - .pdata_size = sizeof(ab8500_bm_data), + .name = "ab8500-usb", + .num_resources = ARRAY_SIZE(ab8500_usb_resources), + .resources = ab8500_usb_resources, }, { - .name = "ab8500-chargalg", - .of_compatible = "stericsson,ab8500-chargalg", - .num_resources = ARRAY_SIZE(ab8500_chargalg_resources), - .resources = ab8500_chargalg_resources, - .platform_data = &ab8500_bm_data, - .pdata_size = sizeof(ab8500_bm_data), + .name = "ab8500-codec", }, }; -static struct mfd_cell ab8500_devs[] = { +static struct mfd_cell ab9540_devs[] = { +#ifdef CONFIG_DEBUG_FS { - .name = "pinctrl-ab8500", - .of_compatible = "stericsson,ab8500-gpio", + .name = "ab8500-debug", + .num_resources = ARRAY_SIZE(ab8500_debug_resources), + .resources = ab8500_debug_resources, }, +#endif { - .name = "ab8500-usb", - .of_compatible = "stericsson,ab8500-usb", - .num_resources = ARRAY_SIZE(ab8500_usb_resources), - .resources = ab8500_usb_resources, + .name = "ab8500-sysctrl", }, { - .name = "ab8500-codec", - .of_compatible = "stericsson,ab8500-codec", + .name = "ab8500-regulator", }, { .name = "ab8500-gpadc", @@ -1127,9 +1144,33 @@ static struct mfd_cell ab8500_devs[] = { .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), .resources = ab8500_gpadc_resources, }, -}; - -static struct mfd_cell ab9540_devs[] = { + { + .name = "ab8500-rtc", + .num_resources = ARRAY_SIZE(ab8500_rtc_resources), + .resources = ab8500_rtc_resources, + }, + { + .name = "ab8500-acc-det", + .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources), + .resources = ab8500_av_acc_detect_resources, + }, + { + .name = "ab8500-poweron-key", + .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources), + .resources = ab8500_poweronkey_db_resources, + }, + { + .name = "ab8500-pwm", + .id = 1, + }, + { + .name = "ab8500-leds", + }, + { + .name = "abx500-temp", + .num_resources = ARRAY_SIZE(ab8500_temp_resources), + .resources = ab8500_temp_resources, + }, { .name = "pinctrl-ab9540", .of_compatible = "stericsson,ab9540-gpio", @@ -1142,11 +1183,6 @@ static struct mfd_cell ab9540_devs[] = { { .name = "ab9540-codec", }, - { - .name = "ab8500-gpadc", - .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), - .resources = ab8500_gpadc_resources, - }, { .name = "ab-iddet", .num_resources = ARRAY_SIZE(ab8505_iddet_resources), @@ -1156,6 +1192,57 @@ static struct mfd_cell ab9540_devs[] = { /* Device list for ab8505 */ static struct mfd_cell ab8505_devs[] = { +#ifdef CONFIG_DEBUG_FS + { + .name = "ab8500-debug", + .num_resources = ARRAY_SIZE(ab8500_debug_resources), + .resources = ab8500_debug_resources, + }, +#endif + { + .name = "ab8500-sysctrl", + }, + { + .name = "ab8500-regulator", + }, + { + .name = "ab8500-gpadc", + .num_resources = ARRAY_SIZE(ab8505_gpadc_resources), + .resources = ab8505_gpadc_resources, + }, + { + .name = "ab8500-rtc", + .num_resources = ARRAY_SIZE(ab8500_rtc_resources), + .resources = ab8500_rtc_resources, + }, + { + .name = "ab8500-acc-det", + .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources), + .resources = ab8500_av_acc_detect_resources, + }, + { + .name = "ab8500-poweron-key", + .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources), + .resources = ab8500_poweronkey_db_resources, + }, + { + .name = "ab8500-pwm", + .id = 1, + }, + { + .name = "ab8500-leds", + }, + { + .name = "ab8500-gpio", + }, + { + .name = "ab8500-usb", + .num_resources = ARRAY_SIZE(ab8500_usb_resources), + .resources = ab8500_usb_resources, + }, + { + .name = "ab8500-codec", + }, { .name = "ab-iddet", .num_resources = ARRAY_SIZE(ab8505_iddet_resources), @@ -1164,6 +1251,51 @@ static struct mfd_cell ab8505_devs[] = { }; static struct mfd_cell ab8540_devs[] = { +#ifdef CONFIG_DEBUG_FS + { + .name = "ab8500-debug", + .num_resources = ARRAY_SIZE(ab8500_debug_resources), + .resources = ab8500_debug_resources, + }, +#endif + { + .name = "ab8500-sysctrl", + }, + { + .name = "ab8500-regulator", + }, + { + .name = "ab8500-gpadc", + .num_resources = ARRAY_SIZE(ab8505_gpadc_resources), + .resources = ab8505_gpadc_resources, + }, + { + .name = "ab8500-rtc", + .num_resources = ARRAY_SIZE(ab8500_rtc_resources), + .resources = ab8500_rtc_resources, + }, + { + .name = "ab8500-acc-det", + .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources), + .resources = ab8500_av_acc_detect_resources, + }, + { + .name = "ab8500-poweron-key", + .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources), + .resources = ab8500_poweronkey_db_resources, + }, + { + .name = "ab8500-pwm", + .id = 1, + }, + { + .name = "ab8500-leds", + }, + { + .name = "abx500-temp", + .num_resources = ARRAY_SIZE(ab8500_temp_resources), + .resources = ab8500_temp_resources, + }, { .name = "ab8500-gpio", }, @@ -1175,11 +1307,6 @@ static struct mfd_cell ab8540_devs[] = { { .name = "ab8540-codec", }, - { - .name = "ab8500-gpadc", - .num_resources = ARRAY_SIZE(ab8540_gpadc_resources), - .resources = ab8540_gpadc_resources, - }, { .name = "ab-iddet", .num_resources = ARRAY_SIZE(ab8505_iddet_resources), @@ -1528,12 +1655,6 @@ static int ab8500_probe(struct platform_device *pdev) return ret; } - ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs, - ARRAY_SIZE(abx500_common_devs), NULL, - ab8500->irq_base, ab8500->domain); - if (ret) - return ret; - if (is_ab9540(ab8500)) ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, ARRAY_SIZE(ab9540_devs), NULL, -- cgit v1.2.3 From 3e1a498f2728476535571d270081a17fdfceaf26 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 25 Feb 2013 14:57:35 +0000 Subject: mfd: ab8500-core: Add Interrupt support for ab8540 ITSource/ITLatch 7, 8, 9 and 10 don't exist on AB8540. This patch replaces them with '-1' in the interrupt list, and handles the '-1' in the code accordingly. Signed-off-by: Lee Jones Acked-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 50 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 7 deletions(-) (limited to 'drivers/mfd/ab8500-core.c') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 23db4fcea496..0ba08a26cf73 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -103,8 +103,10 @@ #define AB8500_IT_LATCHHIER1_REG 0x60 #define AB8500_IT_LATCHHIER2_REG 0x61 #define AB8500_IT_LATCHHIER3_REG 0x62 +#define AB8540_IT_LATCHHIER4_REG 0x63 #define AB8500_IT_LATCHHIER_NUM 3 +#define AB8540_IT_LATCHHIER_NUM 4 #define AB8500_REV_REG 0x80 #define AB8500_IC_NAME_REG 0x82 @@ -143,6 +145,12 @@ static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = { 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 23 }; +/* AB8540 support */ +static const int ab8540_irq_regoffset[AB8540_NUM_IRQ_REGS] = { + 0, 1, 2, 3, 4, -1, -1, -1, -1, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 23, + 25, 26, 27, 28, 29, 30, 31, +}; + static const char ab8500_version_str[][7] = { [AB8500_VERSION_AB8500] = "AB8500", [AB8500_VERSION_AB8505] = "AB8505", @@ -360,6 +368,9 @@ static void ab8500_irq_sync_unlock(struct irq_data *data) is_ab8500_1p1_or_earlier(ab8500)) continue; + if (ab8500->irq_reg_offset[i] < 0) + continue; + ab8500->oldmask[i] = new; reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i]; @@ -431,6 +442,18 @@ static struct irq_chip ab8500_irq_chip = { .irq_set_type = ab8500_irq_set_type, }; +static void update_latch_offset(u8 *offset, int i) +{ + /* Fix inconsistent ITFromLatch25 bit mapping... */ + if (unlikely(*offset == 17)) + *offset = 24; + /* Fix inconsistent ab8540 bit mapping... */ + if (unlikely(*offset == 16)) + *offset = 25; + if ((i==3) && (*offset >= 24)) + *offset += 2; +} + static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, int latch_offset, u8 latch_val) { @@ -482,9 +505,7 @@ static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500, latch_bit = __ffs(hier_val); latch_offset = (hier_offset << 3) + latch_bit; - /* Fix inconsistent ITFromLatch25 bit mapping... */ - if (unlikely(latch_offset == 17)) - latch_offset = 24; + update_latch_offset(&latch_offset, hier_offset); status = get_register_interruptible(ab8500, AB8500_INTERRUPT, @@ -512,7 +533,7 @@ static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev) dev_vdbg(ab8500->dev, "interrupt\n"); /* Hierarchical interrupt version */ - for (i = 0; i < AB8500_IT_LATCHHIER_NUM; i++) { + for (i = 0; i < (ab8500->it_latchhier_num); i++) { int status; u8 hier_val; @@ -565,6 +586,9 @@ static irqreturn_t ab8500_irq(int irq, void *dev) if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500)) continue; + if (regoffset < 0) + continue; + status = get_register_interruptible(ab8500, AB8500_INTERRUPT, AB8500_IT_LATCH1_REG + regoffset, &value); if (status < 0 || value == 0) @@ -615,7 +639,9 @@ static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np) { int num_irqs; - if (is_ab9540(ab8500)) + if (is_ab8540(ab8500)) + num_irqs = AB8540_NR_IRQS; + else if (is_ab9540(ab8500)) num_irqs = AB9540_NR_IRQS; else if (is_ab8505(ab8500)) num_irqs = AB8505_NR_IRQS; @@ -1552,13 +1578,20 @@ static int ab8500_probe(struct platform_device *pdev) ab8500->chip_id >> 4, ab8500->chip_id & 0x0F); - /* Configure AB8500 or AB9540 IRQ */ - if (is_ab9540(ab8500) || is_ab8505(ab8500)) { + /* Configure AB8540 */ + if (is_ab8540(ab8500)) { + ab8500->mask_size = AB8540_NUM_IRQ_REGS; + ab8500->irq_reg_offset = ab8540_irq_regoffset; + ab8500->it_latchhier_num = AB8540_IT_LATCHHIER_NUM; + }/* Configure AB8500 or AB9540 IRQ */ + else if (is_ab9540(ab8500) || is_ab8505(ab8500)) { ab8500->mask_size = AB9540_NUM_IRQ_REGS; ab8500->irq_reg_offset = ab9540_irq_regoffset; + ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM; } else { ab8500->mask_size = AB8500_NUM_IRQ_REGS; ab8500->irq_reg_offset = ab8500_irq_regoffset; + ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM; } ab8500->mask = devm_kzalloc(&pdev->dev, ab8500->mask_size, GFP_KERNEL); if (!ab8500->mask) @@ -1620,6 +1653,9 @@ static int ab8500_probe(struct platform_device *pdev) is_ab8500_1p1_or_earlier(ab8500)) continue; + if (ab8500->irq_reg_offset[i] < 0) + continue; + get_register_interruptible(ab8500, AB8500_INTERRUPT, AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i], &value); -- cgit v1.2.3 From e436ddff5748c459853bb3fb97550a9b8b647b8d Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 26 Feb 2013 10:09:41 +0000 Subject: mfd: ab8500-debugfs: Add tests for ab8540 based platform initialisations Signed-off-by: Alexandre Torgue Signed-off-by: Lee Jones Reviewed-by: Marcus COOPER Reviewed-by: Mattias WALLIN Tested-by: Maxime COQUELIN Acked-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/mfd/ab8500-core.c') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 0ba08a26cf73..0fc18e91310c 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -1346,6 +1346,7 @@ static ssize_t show_chip_id(struct device *dev, struct ab8500 *ab8500; ab8500 = dev_get_drvdata(dev); + return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL); } @@ -1676,7 +1677,7 @@ static int ab8500_probe(struct platform_device *pdev) /* Activate this feature only in ab9540 */ /* till tests are done on ab8500 1p2 or later*/ - if (is_ab9540(ab8500)) { + if (is_ab9540(ab8500) || is_ab8540(ab8500)) ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL, ab8500_hierarchical_irq, IRQF_ONESHOT | IRQF_NO_SUSPEND, @@ -1719,7 +1720,8 @@ static int ab8500_probe(struct platform_device *pdev) dev_err(ab8500->dev, "error adding bm devices\n"); } - if (is_ab9540(ab8500)) + if (((is_ab8505(ab8500) || is_ab9540(ab8500)) && + ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500)) ret = sysfs_create_group(&ab8500->dev->kobj, &ab9540_attr_group); else @@ -1735,7 +1737,8 @@ static int ab8500_remove(struct platform_device *pdev) { struct ab8500 *ab8500 = platform_get_drvdata(pdev); - if (is_ab9540(ab8500)) + if (((is_ab8505(ab8500) || is_ab9540(ab8500)) && + ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500)) sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group); else sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group); -- cgit v1.2.3 From 492390c8fd4a90b1e4ca371c8f8a23c63b04d7f9 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 25 Feb 2013 15:06:18 +0000 Subject: mfd: ab8500-core: Add additional resources to ab8505_iddet_resources Add VBUS_DET_R, VBUS_DET_F IRQ, ID_DET_PLUGR and ID_DET_PLUGF IRQ information to ab8505_iddet_resources. These are required to get interrupts for AB8505 cut-2. Signed-off-by: Lee Jones Acked-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/mfd/ab8500-core.c') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 0fc18e91310c..141572c6c392 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -1016,6 +1016,30 @@ static struct resource ab8505_iddet_resources[] = { .end = AB8505_INT_KEYSTUCK, .flags = IORESOURCE_IRQ, }, + { + .name = "VBUS_DET_R", + .start = AB8500_INT_VBUS_DET_R, + .end = AB8500_INT_VBUS_DET_R, + .flags = IORESOURCE_IRQ, + }, + { + .name = "VBUS_DET_F", + .start = AB8500_INT_VBUS_DET_F, + .end = AB8500_INT_VBUS_DET_F, + .flags = IORESOURCE_IRQ, + }, + { + .name = "ID_DET_PLUGR", + .start = AB8500_INT_ID_DET_PLUGR, + .end = AB8500_INT_ID_DET_PLUGR, + .flags = IORESOURCE_IRQ, + }, + { + .name = "ID_DET_PLUGF", + .start = AB8500_INT_ID_DET_PLUGF, + .end = AB8500_INT_ID_DET_PLUGF, + .flags = IORESOURCE_IRQ, + }, }; static struct resource ab8500_temp_resources[] = { -- cgit v1.2.3 From abee26cdb685fa47d3d17ec9cf39f6149ce67083 Mon Sep 17 00:00:00 2001 From: Mattias Wallin Date: Fri, 28 Sep 2012 09:34:24 +0200 Subject: mfd: ab8500-core: Show turn on status at boot Several states can be detected when a device is initially turned on. This patch displays these states in the log. If none of the states are true, then we report that too. Signed-off-by: Mattias Wallin Signed-off-by: Lee Jones Reviewed-by: Marcus COOPER Reviewed-by: Jonas ABERG Acked-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers/mfd/ab8500-core.c') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 141572c6c392..a4120edbccf2 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -1542,6 +1542,15 @@ static int ab8500_probe(struct platform_device *pdev) "Battery level lower than power on reset threshold", "Power on key 1 pressed longer than 10 seconds", "DB8500 thermal shutdown"}; + static char *turn_on_status[] = { + "Battery rising (Vbat)", + "Power On Key 1 dbF", + "Power On Key 2 dbF", + "RTC Alarm", + "Main Charger Detect", + "Vbus Detect (USB)", + "USB ID Detect", + "UART Factory Mode Detect"}; struct ab8500_platform_data *plat = dev_get_platdata(&pdev->dev); const struct platform_device_id *platid = platform_get_device_id(pdev); enum ab8500_version version = AB8500_VERSION_UNDEFINED; @@ -1655,9 +1664,26 @@ static int ab8500_probe(struct platform_device *pdev) } else { printk(KERN_CONT " None\n"); } + ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, + AB8500_TURN_ON_STATUS, &value); + if (ret < 0) + return ret; + dev_info(ab8500->dev, "turn on reason(s) (%#x): ", value); + + if (value) { + for (i = 0; i < ARRAY_SIZE(turn_on_status); i++) { + if (value & 1) + printk("\"%s\" ", turn_on_status[i]); + value = value >> 1; + } + printk("\n"); + } else { + printk("None\n"); + } if (plat && plat->init) plat->init(ab8500); + if (is_ab9540(ab8500)) { ret = get_register_interruptible(ab8500, AB8500_CHARGER, AB8500_CH_USBCH_STAT1_REG, &value); -- cgit v1.2.3 From 9ee17676a5a36621db020c596e766fec24aae959 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 20 Nov 2012 14:57:25 +0100 Subject: mfd: ab8500-core: Add abx500-clk as an mfd child device Hierarchically, the abx500-clk shall be considered as a child of the ab8500 core. The abx500-clk is intiated at arch init and thus the clks will be available when clients needs them. Signed-off-by: Ulf Hansson Signed-off-by: Lee Jones Reviewed-by: Philippe LANGLAIS Reviewed-by: Patrice CHOTARD Reviewed-by: Gabriel FERNANDEZ Reviewed-by: Philippe BEGNIC Acked-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/mfd/ab8500-core.c') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index a4120edbccf2..caab1fd3a03f 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -1188,6 +1188,10 @@ static struct mfd_cell ab9540_devs[] = { { .name = "ab8500-regulator", }, + { + .name = "abx500-clk", + .of_compatible = "stericsson,abx500-clk", + }, { .name = "ab8500-gpadc", .of_compatible = "stericsson,ab8500-gpadc", @@ -1255,6 +1259,10 @@ static struct mfd_cell ab8505_devs[] = { { .name = "ab8500-regulator", }, + { + .name = "abx500-clk", + .of_compatible = "stericsson,abx500-clk", + }, { .name = "ab8500-gpadc", .num_resources = ARRAY_SIZE(ab8505_gpadc_resources), @@ -1314,6 +1322,10 @@ static struct mfd_cell ab8540_devs[] = { { .name = "ab8500-regulator", }, + { + .name = "abx500-clk", + .of_compatible = "stericsson,abx500-clk", + }, { .name = "ab8500-gpadc", .num_resources = ARRAY_SIZE(ab8505_gpadc_resources), -- cgit v1.2.3 From f348fefd2a227122eb2d723e255c60cf491d0557 Mon Sep 17 00:00:00 2001 From: Dariusz Szymczak Date: Mon, 26 Nov 2012 13:31:26 +0100 Subject: mfd: ab8500-core: Hierarchical interrupt registers Make use of the hierarchical interrupt rergister called ITLatchHier1 - 3 also for the 8500 platform (currently the hierarchical interrupt registers are used only for the 8540 and 9540 platforms). This will make the interrupt routing go faster since fewer i2c reads need to made in the most common cases. Signed-off-by: Dariusz Szymczak Signed-off-by: Lee Jones Reviewed-by: Mian Yousaf KAUKAB Acked-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 82 ++++------------------------------------------- 1 file changed, 6 insertions(+), 76 deletions(-) (limited to 'drivers/mfd/ab8500-core.c') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index caab1fd3a03f..c7ff55753a8f 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -549,66 +549,6 @@ static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev) return IRQ_HANDLED; } -/** - * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ - * - * @ab8500: ab8500_irq controller to operate on. - * @irq: index of the interrupt requested in the chip IRQs - * - * Useful for drivers to request their own IRQs. - */ -static int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq) -{ - if (!ab8500) - return -EINVAL; - - return irq_create_mapping(ab8500->domain, irq); -} - -static irqreturn_t ab8500_irq(int irq, void *dev) -{ - struct ab8500 *ab8500 = dev; - int i; - - dev_vdbg(ab8500->dev, "interrupt\n"); - - atomic_inc(&ab8500->transfer_ongoing); - - for (i = 0; i < ab8500->mask_size; i++) { - int regoffset = ab8500->irq_reg_offset[i]; - int status; - u8 value; - - /* - * Interrupt register 12 doesn't exist prior to AB8500 version - * 2.0 - */ - if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500)) - continue; - - if (regoffset < 0) - continue; - - status = get_register_interruptible(ab8500, AB8500_INTERRUPT, - AB8500_IT_LATCH1_REG + regoffset, &value); - if (status < 0 || value == 0) - continue; - - do { - int bit = __ffs(value); - int line = i * 8 + bit; - int virq = ab8500_irq_get_virq(ab8500, line); - - handle_nested_irq(virq); - ab8500_debug_register_interrupt(line); - value &= ~(1 << bit); - - } while (value); - } - atomic_dec(&ab8500->transfer_ongoing); - return IRQ_HANDLED; -} - static int ab8500_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq) { @@ -1737,22 +1677,12 @@ static int ab8500_probe(struct platform_device *pdev) if (ret) return ret; - /* Activate this feature only in ab9540 */ - /* till tests are done on ab8500 1p2 or later*/ - if (is_ab9540(ab8500) || is_ab8540(ab8500)) - ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL, - ab8500_hierarchical_irq, - IRQF_ONESHOT | IRQF_NO_SUSPEND, - "ab8500", ab8500); - } - else { - ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL, - ab8500_irq, - IRQF_ONESHOT | IRQF_NO_SUSPEND, - "ab8500", ab8500); - if (ret) - return ret; - } + ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL, + ab8500_hierarchical_irq, + IRQF_ONESHOT | IRQF_NO_SUSPEND, + "ab8500", ab8500); + if (ret) + return ret; if (is_ab9540(ab8500)) ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, -- cgit v1.2.3 From 93ff722e88530b9719cbf53be4f3197722461394 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 31 May 2012 16:16:36 +0200 Subject: ab8500-fg: Add power cut feature for ab8505 and ab8540 Add support for a power cut feature which allows user to configure when ab8505 and ab8540 based platforms should shut down system due to low battery. Signed-off-by: Lee Jones --- drivers/mfd/ab8500-core.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'drivers/mfd/ab8500-core.c') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index c7ff55753a8f..f276352cc9ef 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -113,6 +113,7 @@ #define AB8500_SWITCH_OFF_STATUS 0x00 #define AB8500_TURN_ON_STATUS 0x00 +#define AB8505_TURN_ON_STATUS_2 0x04 #define AB8500_CH_USBCH_STAT1_REG 0x02 #define VBUS_DET_DBNC100 0x02 @@ -1401,6 +1402,21 @@ static ssize_t show_turn_on_status(struct device *dev, return sprintf(buf, "%#x\n", value); } +static ssize_t show_turn_on_status_2(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + u8 value; + struct ab8500 *ab8500; + + ab8500 = dev_get_drvdata(dev); + ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, + AB8505_TURN_ON_STATUS_2, &value); + if (ret < 0) + return ret; + return sprintf(buf, "%#x\n", (value & 0x1)); +} + static ssize_t show_ab9540_dbbrstn(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1457,6 +1473,7 @@ exit: static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL); static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL); static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL); +static DEVICE_ATTR(turn_on_status_2, S_IRUGO, show_turn_on_status_2, NULL); static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR, show_ab9540_dbbrstn, store_ab9540_dbbrstn); @@ -1467,6 +1484,11 @@ static struct attribute *ab8500_sysfs_entries[] = { NULL, }; +static struct attribute *ab8505_sysfs_entries[] = { + &dev_attr_turn_on_status_2.attr, + NULL, +}; + static struct attribute *ab9540_sysfs_entries[] = { &dev_attr_chip_id.attr, &dev_attr_switch_off_status.attr, @@ -1479,6 +1501,10 @@ static struct attribute_group ab8500_attr_group = { .attrs = ab8500_sysfs_entries, }; +static struct attribute_group ab8505_attr_group = { + .attrs = ab8505_sysfs_entries, +}; + static struct attribute_group ab9540_attr_group = { .attrs = ab9540_sysfs_entries, }; @@ -1719,6 +1745,12 @@ static int ab8500_probe(struct platform_device *pdev) else ret = sysfs_create_group(&ab8500->dev->kobj, &ab8500_attr_group); + + if ((is_ab8505(ab8500) || is_ab9540(ab8500)) && + ab8500->chip_id >= AB8500_CUT2P0) + ret = sysfs_create_group(&ab8500->dev->kobj, + &ab8505_attr_group); + if (ret) dev_err(ab8500->dev, "error creating sysfs entries\n"); @@ -1735,6 +1767,10 @@ static int ab8500_remove(struct platform_device *pdev) else sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group); + if ((is_ab8505(ab8500) || is_ab9540(ab8500)) && + ab8500->chip_id >= AB8500_CUT2P0) + sysfs_remove_group(&ab8500->dev->kobj, &ab8505_attr_group); + mfd_remove_devices(ab8500->dev); return 0; -- cgit v1.2.3