diff options
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/ab8500-core.c | 14 | ||||
-rw-r--r-- | drivers/mfd/db8500-prcmu.c | 143 | ||||
-rw-r--r-- | drivers/mfd/intel_msic.c | 9 | ||||
-rw-r--r-- | drivers/mfd/sec-core.c | 75 | ||||
-rw-r--r-- | drivers/mfd/vexpress-sysreg.c | 2 | ||||
-rw-r--r-- | drivers/mfd/wm5102-tables.c | 12 | ||||
-rw-r--r-- | drivers/mfd/wm5110-tables.c | 1 |
7 files changed, 183 insertions, 73 deletions
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 5b1c296..7c84ced 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -798,6 +798,12 @@ static struct resource ab8500_charger_resources[] = { .end = AB8500_INT_CH_WD_EXP, .flags = IORESOURCE_IRQ, }, + { + .name = "VBUS_CH_DROP_END", + .start = AB8500_INT_VBUS_CH_DROP_END, + .end = AB8500_INT_VBUS_CH_DROP_END, + .flags = IORESOURCE_IRQ, + }, }; static struct resource ab8500_btemp_resources[] = { @@ -1060,40 +1066,32 @@ static struct mfd_cell ab8500_bm_devs[] = { .of_compatible = "stericsson,ab8500-charger", .num_resources = ARRAY_SIZE(ab8500_charger_resources), .resources = ab8500_charger_resources, -#ifndef CONFIG_OF .platform_data = &ab8500_bm_data, .pdata_size = sizeof(ab8500_bm_data), -#endif }, { .name = "ab8500-btemp", .of_compatible = "stericsson,ab8500-btemp", .num_resources = ARRAY_SIZE(ab8500_btemp_resources), .resources = ab8500_btemp_resources, -#ifndef CONFIG_OF .platform_data = &ab8500_bm_data, .pdata_size = sizeof(ab8500_bm_data), -#endif }, { .name = "ab8500-fg", .of_compatible = "stericsson,ab8500-fg", .num_resources = ARRAY_SIZE(ab8500_fg_resources), .resources = ab8500_fg_resources, -#ifndef CONFIG_OF .platform_data = &ab8500_bm_data, .pdata_size = sizeof(ab8500_bm_data), -#endif }, { .name = "ab8500-chargalg", .of_compatible = "stericsson,ab8500-chargalg", .num_resources = ARRAY_SIZE(ab8500_chargalg_resources), .resources = ab8500_chargalg_resources, -#ifndef CONFIG_OF .platform_data = &ab8500_bm_data, .pdata_size = sizeof(ab8500_bm_data), -#endif }, }; diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index e42a417..21f261b 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -26,6 +26,7 @@ #include <linux/fs.h> #include <linux/platform_device.h> #include <linux/uaccess.h> +#include <linux/irqchip/arm-gic.h> #include <linux/mfd/core.h> #include <linux/mfd/dbx500-prcmu.h> #include <linux/mfd/abx500/ab8500.h> @@ -33,16 +34,11 @@ #include <linux/regulator/machine.h> #include <linux/cpufreq.h> #include <linux/platform_data/ux500_wdt.h> -#include <asm/hardware/gic.h> #include <mach/hardware.h> #include <mach/irqs.h> #include <mach/db8500-regs.h> -#include <mach/id.h> #include "dbx500-prcmu-regs.h" -/* Offset for the firmware version within the TCPM */ -#define PRCMU_FW_VERSION_OFFSET 0xA4 - /* Index of different voltages to be used when accessing AVSData */ #define PRCM_AVS_BASE 0x2FC #define PRCM_AVS_VBB_RET (PRCM_AVS_BASE + 0x0) @@ -217,10 +213,8 @@ #define PRCM_REQ_MB5_I2C_HW_BITS (PRCM_REQ_MB5 + 0x1) #define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 0x2) #define PRCM_REQ_MB5_I2C_VAL (PRCM_REQ_MB5 + 0x3) -#define PRCMU_I2C_WRITE(slave) \ - (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0)) -#define PRCMU_I2C_READ(slave) \ - (((slave) << 1) | BIT(0) | (cpu_is_u8500v2() ? BIT(6) : 0)) +#define PRCMU_I2C_WRITE(slave) (((slave) << 1) | BIT(6)) +#define PRCMU_I2C_READ(slave) (((slave) << 1) | BIT(0) | BIT(6)) #define PRCMU_I2C_STOP_EN BIT(3) /* Mailbox 5 ACKs */ @@ -1050,12 +1044,13 @@ int db8500_prcmu_get_ddr_opp(void) * * This function sets the operating point of the DDR. */ +static bool enable_set_ddr_opp; int db8500_prcmu_set_ddr_opp(u8 opp) { if (opp < DDR_100_OPP || opp > DDR_25_OPP) return -EINVAL; /* Changing the DDR OPP can hang the hardware pre-v21 */ - if (cpu_is_u8500v20_or_later() && !cpu_is_u8500v20()) + if (enable_set_ddr_opp) writeb(opp, PRCM_DDR_SUBSYS_APE_MINBW); return 0; @@ -2712,21 +2707,43 @@ static struct irq_chip prcmu_irq_chip = { .irq_unmask = prcmu_irq_unmask, }; -static char *fw_project_name(u8 project) +static __init char *fw_project_name(u32 project) { switch (project) { case PRCMU_FW_PROJECT_U8500: return "U8500"; - case PRCMU_FW_PROJECT_U8500_C2: - return "U8500 C2"; + case PRCMU_FW_PROJECT_U8400: + return "U8400"; case PRCMU_FW_PROJECT_U9500: return "U9500"; - case PRCMU_FW_PROJECT_U9500_C2: - return "U9500 C2"; + case PRCMU_FW_PROJECT_U8500_MBB: + return "U8500 MBB"; + case PRCMU_FW_PROJECT_U8500_C1: + return "U8500 C1"; + case PRCMU_FW_PROJECT_U8500_C2: + return "U8500 C2"; + case PRCMU_FW_PROJECT_U8500_C3: + return "U8500 C3"; + case PRCMU_FW_PROJECT_U8500_C4: + return "U8500 C4"; + case PRCMU_FW_PROJECT_U9500_MBL: + return "U9500 MBL"; + case PRCMU_FW_PROJECT_U8500_MBL: + return "U8500 MBL"; + case PRCMU_FW_PROJECT_U8500_MBL2: + return "U8500 MBL2"; case PRCMU_FW_PROJECT_U8520: - return "U8520"; + return "U8520 MBL"; case PRCMU_FW_PROJECT_U8420: return "U8420"; + case PRCMU_FW_PROJECT_U9540: + return "U9540"; + case PRCMU_FW_PROJECT_A9420: + return "A9420"; + case PRCMU_FW_PROJECT_L8540: + return "L8540"; + case PRCMU_FW_PROJECT_L8580: + return "L8580"; default: return "Unknown"; } @@ -2772,36 +2789,44 @@ static int db8500_irq_init(struct device_node *np) return 0; } -void __init db8500_prcmu_early_init(void) +static void dbx500_fw_version_init(struct platform_device *pdev, + u32 version_offset) { - if (cpu_is_u8500v2() || cpu_is_u9540()) { - void *tcpm_base = ioremap_nocache(U8500_PRCMU_TCPM_BASE, SZ_4K); - - if (tcpm_base != NULL) { - u32 version; - version = readl(tcpm_base + PRCMU_FW_VERSION_OFFSET); - fw_info.version.project = version & 0xFF; - fw_info.version.api_version = (version >> 8) & 0xFF; - fw_info.version.func_version = (version >> 16) & 0xFF; - fw_info.version.errata = (version >> 24) & 0xFF; - fw_info.valid = true; - pr_info("PRCMU firmware: %s, version %d.%d.%d\n", - fw_project_name(fw_info.version.project), - (version >> 8) & 0xFF, (version >> 16) & 0xFF, - (version >> 24) & 0xFF); - iounmap(tcpm_base); - } + struct resource *res; + void __iomem *tcpm_base; - if (cpu_is_u9540()) - tcdm_base = ioremap_nocache(U8500_PRCMU_TCDM_BASE, - SZ_4K + SZ_8K) + SZ_8K; - else - tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE); - } else { - pr_err("prcmu: Unsupported chip version\n"); - BUG(); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "prcmu-tcpm"); + if (!res) { + dev_err(&pdev->dev, + "Error: no prcmu tcpm memory region provided\n"); + return; } + tcpm_base = ioremap(res->start, resource_size(res)); + if (tcpm_base != NULL) { + u32 version; + + version = readl(tcpm_base + version_offset); + fw_info.version.project = (version & 0xFF); + fw_info.version.api_version = (version >> 8) & 0xFF; + fw_info.version.func_version = (version >> 16) & 0xFF; + fw_info.version.errata = (version >> 24) & 0xFF; + strncpy(fw_info.version.project_name, + fw_project_name(fw_info.version.project), + PRCMU_FW_PROJECT_NAME_LEN); + fw_info.valid = true; + pr_info("PRCMU firmware: %s(%d), version %d.%d.%d\n", + fw_info.version.project_name, + fw_info.version.project, + fw_info.version.api_version, + fw_info.version.func_version, + fw_info.version.errata); + iounmap(tcpm_base); + } +} +void __init db8500_prcmu_early_init(void) +{ spin_lock_init(&mb0_transfer.lock); spin_lock_init(&mb0_transfer.dbb_irqs_lock); mutex_init(&mb0_transfer.ac_wake_lock); @@ -3088,8 +3113,8 @@ static struct mfd_cell db8500_prcmu_devs[] = { .pdata_size = sizeof(db8500_regulators), }, { - .name = "cpufreq-u8500", - .of_compatible = "stericsson,cpufreq-u8500", + .name = "cpufreq-ux500", + .of_compatible = "stericsson,cpufreq-ux500", .platform_data = &db8500_cpufreq_table, .pdata_size = sizeof(db8500_cpufreq_table), }, @@ -3122,23 +3147,30 @@ static void db8500_prcmu_update_cpufreq(void) */ static int db8500_prcmu_probe(struct platform_device *pdev) { - struct ab8500_platform_data *ab8500_platdata = pdev->dev.platform_data; struct device_node *np = pdev->dev.of_node; + struct prcmu_pdata *pdata = dev_get_platdata(&pdev->dev); int irq = 0, err = 0, i; - - if (ux500_is_svp()) - return -ENODEV; + struct resource *res; init_prcm_registers(); + dbx500_fw_version_init(pdev, pdata->version_offset); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcmu-tcdm"); + if (!res) { + dev_err(&pdev->dev, "no prcmu tcdm region provided\n"); + return -ENOENT; + } + tcdm_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + /* Clean up the mailbox interrupts after pre-kernel code. */ writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR); - if (np) - irq = platform_get_irq(pdev, 0); - - if (!np || irq <= 0) - irq = IRQ_DB8500_PRCMU1; + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(&pdev->dev, "no prcmu irq provided\n"); + return -ENOENT; + } err = request_threaded_irq(irq, prcmu_irq_handler, prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL); @@ -3152,13 +3184,12 @@ static int db8500_prcmu_probe(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(db8500_prcmu_devs); i++) { if (!strcmp(db8500_prcmu_devs[i].name, "ab8500-core")) { - db8500_prcmu_devs[i].platform_data = ab8500_platdata; + db8500_prcmu_devs[i].platform_data = pdata->ab_platdata; db8500_prcmu_devs[i].pdata_size = sizeof(struct ab8500_platform_data); } } - if (cpu_is_u8500v20_or_later()) - prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET); + prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET); db8500_prcmu_update_cpufreq(); diff --git a/drivers/mfd/intel_msic.c b/drivers/mfd/intel_msic.c index ab8d0b2..1804331 100644 --- a/drivers/mfd/intel_msic.c +++ b/drivers/mfd/intel_msic.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ +#include <linux/err.h> #include <linux/gpio.h> #include <linux/io.h> #include <linux/module.h> @@ -424,11 +425,9 @@ static int intel_msic_probe(struct platform_device *pdev) return -ENODEV; } - msic->irq_base = devm_request_and_ioremap(&pdev->dev, res); - if (!msic->irq_base) { - dev_err(&pdev->dev, "failed to map SRAM memory\n"); - return -ENOMEM; - } + msic->irq_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(msic->irq_base)) + return PTR_ERR(msic->irq_base); platform_set_drvdata(pdev, msic); diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 49d361a..77ee26ef 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -17,6 +17,7 @@ #include <linux/err.h> #include <linux/slab.h> #include <linux/i2c.h> +#include <linux/of_irq.h> #include <linux/interrupt.h> #include <linux/pm_runtime.h> #include <linux/mutex.h> @@ -60,6 +61,15 @@ static struct mfd_cell s2mps11_devs[] = { }, }; +#ifdef CONFIG_OF +static struct of_device_id sec_dt_match[] = { + { .compatible = "samsung,s5m8767-pmic", + .data = (void *)S5M8767X, + }, + {}, +}; +#endif + int sec_reg_read(struct sec_pmic_dev *sec_pmic, u8 reg, void *dest) { return regmap_read(sec_pmic->regmap, reg, dest); @@ -95,6 +105,57 @@ static struct regmap_config sec_regmap_config = { .val_bits = 8, }; + +#ifdef CONFIG_OF +/* + * Only the common platform data elements for s5m8767 are parsed here from the + * device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and + * others have to parse their own platform data elements from device tree. + * + * The s5m8767 platform data structure is instantiated here and the drivers for + * the sub-modules need not instantiate another instance while parsing their + * platform data. + */ +static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( + struct device *dev) +{ + struct sec_platform_data *pd; + + pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); + if (!pd) { + dev_err(dev, "could not allocate memory for pdata\n"); + return ERR_PTR(-ENOMEM); + } + + /* + * ToDo: the 'wakeup' member in the platform data is more of a linux + * specfic information. Hence, there is no binding for that yet and + * not parsed here. + */ + + return pd; +} +#else +static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( + struct device *dev) +{ + return 0; +} +#endif + +static inline int sec_i2c_get_driver_data(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ +#ifdef CONFIG_OF + if (i2c->dev.of_node) { + const struct of_device_id *match; + match = of_match_node(sec_dt_match, i2c->dev.of_node); + return (int)match->data; + } +#endif + return (int)id->driver_data; +} + static int sec_pmic_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -111,13 +172,22 @@ static int sec_pmic_probe(struct i2c_client *i2c, sec_pmic->dev = &i2c->dev; sec_pmic->i2c = i2c; sec_pmic->irq = i2c->irq; - sec_pmic->type = id->driver_data; - + sec_pmic->type = sec_i2c_get_driver_data(i2c, id); + + if (sec_pmic->dev->of_node) { + pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev); + if (IS_ERR(pdata)) { + ret = PTR_ERR(pdata); + return ret; + } + pdata->device_type = sec_pmic->type; + } if (pdata) { sec_pmic->device_type = pdata->device_type; sec_pmic->ono = pdata->ono; sec_pmic->irq_base = pdata->irq_base; sec_pmic->wakeup = pdata->wakeup; + sec_pmic->pdata = pdata; } sec_pmic->regmap = devm_regmap_init_i2c(i2c, &sec_regmap_config); @@ -192,6 +262,7 @@ static struct i2c_driver sec_pmic_driver = { .driver = { .name = "sec_pmic", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(sec_dt_match), }, .probe = sec_pmic_probe, .remove = sec_pmic_remove, diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c index a4a43230..bf75e96 100644 --- a/drivers/mfd/vexpress-sysreg.c +++ b/drivers/mfd/vexpress-sysreg.c @@ -315,7 +315,7 @@ static void vexpress_sysreg_config_complete(unsigned long data) } -void __init vexpress_sysreg_setup(struct device_node *node) +void vexpress_sysreg_setup(struct device_node *node) { if (WARN_ON(!vexpress_sysreg_base)) return; diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index d754596..a433f58 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c @@ -85,6 +85,12 @@ int wm5102_patch(struct arizona *arizona) } static const struct regmap_irq wm5102_aod_irqs[ARIZONA_NUM_IRQ] = { + [ARIZONA_IRQ_MICD_CLAMP_FALL] = { + .mask = ARIZONA_MICD_CLAMP_FALL_EINT1 + }, + [ARIZONA_IRQ_MICD_CLAMP_RISE] = { + .mask = ARIZONA_MICD_CLAMP_RISE_EINT1 + }, [ARIZONA_IRQ_GP5_FALL] = { .mask = ARIZONA_GP5_FALL_EINT1 }, [ARIZONA_IRQ_GP5_RISE] = { .mask = ARIZONA_GP5_RISE_EINT1 }, [ARIZONA_IRQ_JD_FALL] = { .mask = ARIZONA_JD1_FALL_EINT1 }, @@ -97,6 +103,7 @@ const struct regmap_irq_chip wm5102_aod = { .mask_base = ARIZONA_AOD_IRQ_MASK_IRQ1, .ack_base = ARIZONA_AOD_IRQ1, .wake_base = ARIZONA_WAKE_CONTROL, + .wake_invert = 1, .num_regs = 1, .irqs = wm5102_aod_irqs, .num_irqs = ARRAY_SIZE(wm5102_aod_irqs), @@ -320,7 +327,7 @@ static const struct reg_default wm5102_reg_default[] = { { 0x0000029B, 0x0020 }, /* R667 - Headphone Detect 1 */ { 0x0000029C, 0x0000 }, /* R668 - Headphone Detect 2 */ { 0x0000029F, 0x0000 }, /* R671 - Headphone Detect Test */ - { 0x000002A2, 0x0000 }, /* R674 - Micd Clamp control */ + { 0x000002A2, 0x0000 }, /* R674 - Micd clamp control */ { 0x000002A3, 0x1102 }, /* R675 - Mic Detect 1 */ { 0x000002A4, 0x009F }, /* R676 - Mic Detect 2 */ { 0x000002A5, 0x0000 }, /* R677 - Mic Detect 3 */ @@ -1078,6 +1085,8 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg) case ARIZONA_ACCESSORY_DETECT_MODE_1: case ARIZONA_HEADPHONE_DETECT_1: case ARIZONA_HEADPHONE_DETECT_2: + case ARIZONA_HP_DACVAL: + case ARIZONA_MICD_CLAMP_CONTROL: case ARIZONA_MIC_DETECT_1: case ARIZONA_MIC_DETECT_2: case ARIZONA_MIC_DETECT_3: @@ -1858,6 +1867,7 @@ static bool wm5102_volatile_register(struct device *dev, unsigned int reg) case ARIZONA_DSP1_SCRATCH_2: case ARIZONA_DSP1_SCRATCH_3: case ARIZONA_HEADPHONE_DETECT_2: + case ARIZONA_HP_DACVAL: case ARIZONA_MIC_DETECT_3: return true; default: diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index adda6b1..c415998 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -255,6 +255,7 @@ const struct regmap_irq_chip wm5110_aod = { .mask_base = ARIZONA_AOD_IRQ_MASK_IRQ1, .ack_base = ARIZONA_AOD_IRQ1, .wake_base = ARIZONA_WAKE_CONTROL, + .wake_invert = 1, .num_regs = 1, .irqs = wm5110_aod_irqs, .num_irqs = ARRAY_SIZE(wm5110_aod_irqs), |