12945fbc2SGraeme Gregory /* 22945fbc2SGraeme Gregory * TI Palmas MFD Driver 32945fbc2SGraeme Gregory * 42945fbc2SGraeme Gregory * Copyright 2011-2012 Texas Instruments Inc. 52945fbc2SGraeme Gregory * 62945fbc2SGraeme Gregory * Author: Graeme Gregory <gg@slimlogic.co.uk> 72945fbc2SGraeme Gregory * 82945fbc2SGraeme Gregory * This program is free software; you can redistribute it and/or modify it 92945fbc2SGraeme Gregory * under the terms of the GNU General Public License as published by the 102945fbc2SGraeme Gregory * Free Software Foundation; either version 2 of the License, or (at your 112945fbc2SGraeme Gregory * option) any later version. 122945fbc2SGraeme Gregory * 132945fbc2SGraeme Gregory */ 142945fbc2SGraeme Gregory 152945fbc2SGraeme Gregory #include <linux/module.h> 162945fbc2SGraeme Gregory #include <linux/moduleparam.h> 172945fbc2SGraeme Gregory #include <linux/init.h> 182945fbc2SGraeme Gregory #include <linux/slab.h> 192945fbc2SGraeme Gregory #include <linux/i2c.h> 202945fbc2SGraeme Gregory #include <linux/interrupt.h> 212945fbc2SGraeme Gregory #include <linux/irq.h> 222945fbc2SGraeme Gregory #include <linux/regmap.h> 232945fbc2SGraeme Gregory #include <linux/err.h> 242945fbc2SGraeme Gregory #include <linux/mfd/core.h> 252945fbc2SGraeme Gregory #include <linux/mfd/palmas.h> 261ffb0be3SJ Keerthy #include <linux/of_device.h> 272945fbc2SGraeme Gregory 282945fbc2SGraeme Gregory static const struct regmap_config palmas_regmap_config[PALMAS_NUM_CLIENTS] = { 292945fbc2SGraeme Gregory { 302945fbc2SGraeme Gregory .reg_bits = 8, 312945fbc2SGraeme Gregory .val_bits = 8, 322945fbc2SGraeme Gregory .max_register = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE, 332945fbc2SGraeme Gregory PALMAS_PRIMARY_SECONDARY_PAD3), 342945fbc2SGraeme Gregory }, 352945fbc2SGraeme Gregory { 362945fbc2SGraeme Gregory .reg_bits = 8, 372945fbc2SGraeme Gregory .val_bits = 8, 382945fbc2SGraeme Gregory .max_register = PALMAS_BASE_TO_REG(PALMAS_GPADC_BASE, 392945fbc2SGraeme Gregory PALMAS_GPADC_SMPS_VSEL_MONITORING), 402945fbc2SGraeme Gregory }, 412945fbc2SGraeme Gregory { 422945fbc2SGraeme Gregory .reg_bits = 8, 432945fbc2SGraeme Gregory .val_bits = 8, 442945fbc2SGraeme Gregory .max_register = PALMAS_BASE_TO_REG(PALMAS_TRIM_GPADC_BASE, 452945fbc2SGraeme Gregory PALMAS_GPADC_TRIM16), 462945fbc2SGraeme Gregory }, 472945fbc2SGraeme Gregory }; 482945fbc2SGraeme Gregory 492945fbc2SGraeme Gregory static const struct regmap_irq palmas_irqs[] = { 502945fbc2SGraeme Gregory /* INT1 IRQs */ 512945fbc2SGraeme Gregory [PALMAS_CHARG_DET_N_VBUS_OVV_IRQ] = { 522945fbc2SGraeme Gregory .mask = PALMAS_INT1_STATUS_CHARG_DET_N_VBUS_OVV, 532945fbc2SGraeme Gregory }, 542945fbc2SGraeme Gregory [PALMAS_PWRON_IRQ] = { 552945fbc2SGraeme Gregory .mask = PALMAS_INT1_STATUS_PWRON, 562945fbc2SGraeme Gregory }, 572945fbc2SGraeme Gregory [PALMAS_LONG_PRESS_KEY_IRQ] = { 582945fbc2SGraeme Gregory .mask = PALMAS_INT1_STATUS_LONG_PRESS_KEY, 592945fbc2SGraeme Gregory }, 602945fbc2SGraeme Gregory [PALMAS_RPWRON_IRQ] = { 612945fbc2SGraeme Gregory .mask = PALMAS_INT1_STATUS_RPWRON, 622945fbc2SGraeme Gregory }, 632945fbc2SGraeme Gregory [PALMAS_PWRDOWN_IRQ] = { 642945fbc2SGraeme Gregory .mask = PALMAS_INT1_STATUS_PWRDOWN, 652945fbc2SGraeme Gregory }, 662945fbc2SGraeme Gregory [PALMAS_HOTDIE_IRQ] = { 672945fbc2SGraeme Gregory .mask = PALMAS_INT1_STATUS_HOTDIE, 682945fbc2SGraeme Gregory }, 692945fbc2SGraeme Gregory [PALMAS_VSYS_MON_IRQ] = { 702945fbc2SGraeme Gregory .mask = PALMAS_INT1_STATUS_VSYS_MON, 712945fbc2SGraeme Gregory }, 722945fbc2SGraeme Gregory [PALMAS_VBAT_MON_IRQ] = { 732945fbc2SGraeme Gregory .mask = PALMAS_INT1_STATUS_VBAT_MON, 742945fbc2SGraeme Gregory }, 752945fbc2SGraeme Gregory /* INT2 IRQs*/ 762945fbc2SGraeme Gregory [PALMAS_RTC_ALARM_IRQ] = { 772945fbc2SGraeme Gregory .mask = PALMAS_INT2_STATUS_RTC_ALARM, 782945fbc2SGraeme Gregory .reg_offset = 1, 792945fbc2SGraeme Gregory }, 802945fbc2SGraeme Gregory [PALMAS_RTC_TIMER_IRQ] = { 812945fbc2SGraeme Gregory .mask = PALMAS_INT2_STATUS_RTC_TIMER, 822945fbc2SGraeme Gregory .reg_offset = 1, 832945fbc2SGraeme Gregory }, 842945fbc2SGraeme Gregory [PALMAS_WDT_IRQ] = { 852945fbc2SGraeme Gregory .mask = PALMAS_INT2_STATUS_WDT, 862945fbc2SGraeme Gregory .reg_offset = 1, 872945fbc2SGraeme Gregory }, 882945fbc2SGraeme Gregory [PALMAS_BATREMOVAL_IRQ] = { 892945fbc2SGraeme Gregory .mask = PALMAS_INT2_STATUS_BATREMOVAL, 902945fbc2SGraeme Gregory .reg_offset = 1, 912945fbc2SGraeme Gregory }, 922945fbc2SGraeme Gregory [PALMAS_RESET_IN_IRQ] = { 932945fbc2SGraeme Gregory .mask = PALMAS_INT2_STATUS_RESET_IN, 942945fbc2SGraeme Gregory .reg_offset = 1, 952945fbc2SGraeme Gregory }, 962945fbc2SGraeme Gregory [PALMAS_FBI_BB_IRQ] = { 972945fbc2SGraeme Gregory .mask = PALMAS_INT2_STATUS_FBI_BB, 982945fbc2SGraeme Gregory .reg_offset = 1, 992945fbc2SGraeme Gregory }, 1002945fbc2SGraeme Gregory [PALMAS_SHORT_IRQ] = { 1012945fbc2SGraeme Gregory .mask = PALMAS_INT2_STATUS_SHORT, 1022945fbc2SGraeme Gregory .reg_offset = 1, 1032945fbc2SGraeme Gregory }, 1042945fbc2SGraeme Gregory [PALMAS_VAC_ACOK_IRQ] = { 1052945fbc2SGraeme Gregory .mask = PALMAS_INT2_STATUS_VAC_ACOK, 1062945fbc2SGraeme Gregory .reg_offset = 1, 1072945fbc2SGraeme Gregory }, 1082945fbc2SGraeme Gregory /* INT3 IRQs */ 1092945fbc2SGraeme Gregory [PALMAS_GPADC_AUTO_0_IRQ] = { 1102945fbc2SGraeme Gregory .mask = PALMAS_INT3_STATUS_GPADC_AUTO_0, 1112945fbc2SGraeme Gregory .reg_offset = 2, 1122945fbc2SGraeme Gregory }, 1132945fbc2SGraeme Gregory [PALMAS_GPADC_AUTO_1_IRQ] = { 1142945fbc2SGraeme Gregory .mask = PALMAS_INT3_STATUS_GPADC_AUTO_1, 1152945fbc2SGraeme Gregory .reg_offset = 2, 1162945fbc2SGraeme Gregory }, 1172945fbc2SGraeme Gregory [PALMAS_GPADC_EOC_SW_IRQ] = { 1182945fbc2SGraeme Gregory .mask = PALMAS_INT3_STATUS_GPADC_EOC_SW, 1192945fbc2SGraeme Gregory .reg_offset = 2, 1202945fbc2SGraeme Gregory }, 1212945fbc2SGraeme Gregory [PALMAS_GPADC_EOC_RT_IRQ] = { 1222945fbc2SGraeme Gregory .mask = PALMAS_INT3_STATUS_GPADC_EOC_RT, 1232945fbc2SGraeme Gregory .reg_offset = 2, 1242945fbc2SGraeme Gregory }, 1252945fbc2SGraeme Gregory [PALMAS_ID_OTG_IRQ] = { 1262945fbc2SGraeme Gregory .mask = PALMAS_INT3_STATUS_ID_OTG, 1272945fbc2SGraeme Gregory .reg_offset = 2, 1282945fbc2SGraeme Gregory }, 1292945fbc2SGraeme Gregory [PALMAS_ID_IRQ] = { 1302945fbc2SGraeme Gregory .mask = PALMAS_INT3_STATUS_ID, 1312945fbc2SGraeme Gregory .reg_offset = 2, 1322945fbc2SGraeme Gregory }, 1332945fbc2SGraeme Gregory [PALMAS_VBUS_OTG_IRQ] = { 1342945fbc2SGraeme Gregory .mask = PALMAS_INT3_STATUS_VBUS_OTG, 1352945fbc2SGraeme Gregory .reg_offset = 2, 1362945fbc2SGraeme Gregory }, 1372945fbc2SGraeme Gregory [PALMAS_VBUS_IRQ] = { 1382945fbc2SGraeme Gregory .mask = PALMAS_INT3_STATUS_VBUS, 1392945fbc2SGraeme Gregory .reg_offset = 2, 1402945fbc2SGraeme Gregory }, 1412945fbc2SGraeme Gregory /* INT4 IRQs */ 1422945fbc2SGraeme Gregory [PALMAS_GPIO_0_IRQ] = { 1432945fbc2SGraeme Gregory .mask = PALMAS_INT4_STATUS_GPIO_0, 1442945fbc2SGraeme Gregory .reg_offset = 3, 1452945fbc2SGraeme Gregory }, 1462945fbc2SGraeme Gregory [PALMAS_GPIO_1_IRQ] = { 1472945fbc2SGraeme Gregory .mask = PALMAS_INT4_STATUS_GPIO_1, 1482945fbc2SGraeme Gregory .reg_offset = 3, 1492945fbc2SGraeme Gregory }, 1502945fbc2SGraeme Gregory [PALMAS_GPIO_2_IRQ] = { 1512945fbc2SGraeme Gregory .mask = PALMAS_INT4_STATUS_GPIO_2, 1522945fbc2SGraeme Gregory .reg_offset = 3, 1532945fbc2SGraeme Gregory }, 1542945fbc2SGraeme Gregory [PALMAS_GPIO_3_IRQ] = { 1552945fbc2SGraeme Gregory .mask = PALMAS_INT4_STATUS_GPIO_3, 1562945fbc2SGraeme Gregory .reg_offset = 3, 1572945fbc2SGraeme Gregory }, 1582945fbc2SGraeme Gregory [PALMAS_GPIO_4_IRQ] = { 1592945fbc2SGraeme Gregory .mask = PALMAS_INT4_STATUS_GPIO_4, 1602945fbc2SGraeme Gregory .reg_offset = 3, 1612945fbc2SGraeme Gregory }, 1622945fbc2SGraeme Gregory [PALMAS_GPIO_5_IRQ] = { 1632945fbc2SGraeme Gregory .mask = PALMAS_INT4_STATUS_GPIO_5, 1642945fbc2SGraeme Gregory .reg_offset = 3, 1652945fbc2SGraeme Gregory }, 1662945fbc2SGraeme Gregory [PALMAS_GPIO_6_IRQ] = { 1672945fbc2SGraeme Gregory .mask = PALMAS_INT4_STATUS_GPIO_6, 1682945fbc2SGraeme Gregory .reg_offset = 3, 1692945fbc2SGraeme Gregory }, 1702945fbc2SGraeme Gregory [PALMAS_GPIO_7_IRQ] = { 1712945fbc2SGraeme Gregory .mask = PALMAS_INT4_STATUS_GPIO_7, 1722945fbc2SGraeme Gregory .reg_offset = 3, 1732945fbc2SGraeme Gregory }, 1742945fbc2SGraeme Gregory }; 1752945fbc2SGraeme Gregory 1762945fbc2SGraeme Gregory static struct regmap_irq_chip palmas_irq_chip = { 1772945fbc2SGraeme Gregory .name = "palmas", 1782945fbc2SGraeme Gregory .irqs = palmas_irqs, 1792945fbc2SGraeme Gregory .num_irqs = ARRAY_SIZE(palmas_irqs), 1802945fbc2SGraeme Gregory 1812945fbc2SGraeme Gregory .num_regs = 4, 1822945fbc2SGraeme Gregory .irq_reg_stride = 5, 1832945fbc2SGraeme Gregory .status_base = PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE, 1842945fbc2SGraeme Gregory PALMAS_INT1_STATUS), 1852945fbc2SGraeme Gregory .mask_base = PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE, 1862945fbc2SGraeme Gregory PALMAS_INT1_MASK), 1872945fbc2SGraeme Gregory }; 1882945fbc2SGraeme Gregory 189df545d1cSLaxman Dewangan static int palmas_set_pdata_irq_flag(struct i2c_client *i2c, 1909c14ac33SGraeme Gregory struct palmas_platform_data *pdata) 1919c14ac33SGraeme Gregory { 192df545d1cSLaxman Dewangan struct irq_data *irq_data = irq_get_irq_data(i2c->irq); 193df545d1cSLaxman Dewangan if (!irq_data) { 194df545d1cSLaxman Dewangan dev_err(&i2c->dev, "Invalid IRQ: %d\n", i2c->irq); 195df545d1cSLaxman Dewangan return -EINVAL; 196df545d1cSLaxman Dewangan } 197df545d1cSLaxman Dewangan 198df545d1cSLaxman Dewangan pdata->irq_flags = irqd_get_trigger_type(irq_data); 199df545d1cSLaxman Dewangan dev_info(&i2c->dev, "Irq flag is 0x%08x\n", pdata->irq_flags); 200df545d1cSLaxman Dewangan return 0; 201df545d1cSLaxman Dewangan } 202df545d1cSLaxman Dewangan 203df545d1cSLaxman Dewangan static void palmas_dt_to_pdata(struct i2c_client *i2c, 204df545d1cSLaxman Dewangan struct palmas_platform_data *pdata) 205df545d1cSLaxman Dewangan { 206df545d1cSLaxman Dewangan struct device_node *node = i2c->dev.of_node; 2079c14ac33SGraeme Gregory int ret; 2089c14ac33SGraeme Gregory u32 prop; 2099c14ac33SGraeme Gregory 2102154a2b3SJ Keerthy ret = of_property_read_u32(node, "ti,mux-pad1", &prop); 2119c14ac33SGraeme Gregory if (!ret) { 2129c14ac33SGraeme Gregory pdata->mux_from_pdata = 1; 2139c14ac33SGraeme Gregory pdata->pad1 = prop; 2149c14ac33SGraeme Gregory } 2159c14ac33SGraeme Gregory 2162154a2b3SJ Keerthy ret = of_property_read_u32(node, "ti,mux-pad2", &prop); 2179c14ac33SGraeme Gregory if (!ret) { 2189c14ac33SGraeme Gregory pdata->mux_from_pdata = 1; 2199c14ac33SGraeme Gregory pdata->pad2 = prop; 2209c14ac33SGraeme Gregory } 2219c14ac33SGraeme Gregory 2229c14ac33SGraeme Gregory /* The default for this register is all masked */ 2232154a2b3SJ Keerthy ret = of_property_read_u32(node, "ti,power-ctrl", &prop); 2249c14ac33SGraeme Gregory if (!ret) 2259c14ac33SGraeme Gregory pdata->power_ctrl = prop; 2269c14ac33SGraeme Gregory else 2279c14ac33SGraeme Gregory pdata->power_ctrl = PALMAS_POWER_CTRL_NSLEEP_MASK | 2289c14ac33SGraeme Gregory PALMAS_POWER_CTRL_ENABLE1_MASK | 2299c14ac33SGraeme Gregory PALMAS_POWER_CTRL_ENABLE2_MASK; 230df545d1cSLaxman Dewangan if (i2c->irq) 231df545d1cSLaxman Dewangan palmas_set_pdata_irq_flag(i2c, pdata); 2329c14ac33SGraeme Gregory } 2339c14ac33SGraeme Gregory 2341ffb0be3SJ Keerthy static unsigned int palmas_features = PALMAS_PMIC_FEATURE_SMPS10_BOOST; 2354124e6e2SJ Keerthy static unsigned int tps659038_features; 2361ffb0be3SJ Keerthy 2371ffb0be3SJ Keerthy static const struct of_device_id of_palmas_match_tbl[] = { 2381ffb0be3SJ Keerthy { 2391ffb0be3SJ Keerthy .compatible = "ti,palmas", 2401ffb0be3SJ Keerthy .data = &palmas_features, 2411ffb0be3SJ Keerthy }, 2424124e6e2SJ Keerthy { 2434124e6e2SJ Keerthy .compatible = "ti,tps659038", 2444124e6e2SJ Keerthy .data = &tps659038_features, 2454124e6e2SJ Keerthy }, 2461ffb0be3SJ Keerthy { }, 2471ffb0be3SJ Keerthy }; 2481ffb0be3SJ Keerthy 249f791be49SBill Pemberton static int palmas_i2c_probe(struct i2c_client *i2c, 2502945fbc2SGraeme Gregory const struct i2c_device_id *id) 2512945fbc2SGraeme Gregory { 2522945fbc2SGraeme Gregory struct palmas *palmas; 2532945fbc2SGraeme Gregory struct palmas_platform_data *pdata; 2549c14ac33SGraeme Gregory struct device_node *node = i2c->dev.of_node; 2552945fbc2SGraeme Gregory int ret = 0, i; 2561ffb0be3SJ Keerthy unsigned int reg, addr, *features; 2572945fbc2SGraeme Gregory int slave; 2581ffb0be3SJ Keerthy const struct of_device_id *match; 2592945fbc2SGraeme Gregory 2602945fbc2SGraeme Gregory pdata = dev_get_platdata(&i2c->dev); 2619c14ac33SGraeme Gregory 2629c14ac33SGraeme Gregory if (node && !pdata) { 2639c14ac33SGraeme Gregory pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL); 2649c14ac33SGraeme Gregory 2659c14ac33SGraeme Gregory if (!pdata) 2669c14ac33SGraeme Gregory return -ENOMEM; 2679c14ac33SGraeme Gregory 268df545d1cSLaxman Dewangan palmas_dt_to_pdata(i2c, pdata); 2699c14ac33SGraeme Gregory } 2709c14ac33SGraeme Gregory 2712945fbc2SGraeme Gregory if (!pdata) 2722945fbc2SGraeme Gregory return -EINVAL; 2732945fbc2SGraeme Gregory 2742945fbc2SGraeme Gregory palmas = devm_kzalloc(&i2c->dev, sizeof(struct palmas), GFP_KERNEL); 2752945fbc2SGraeme Gregory if (palmas == NULL) 2762945fbc2SGraeme Gregory return -ENOMEM; 2772945fbc2SGraeme Gregory 2782945fbc2SGraeme Gregory i2c_set_clientdata(i2c, palmas); 2792945fbc2SGraeme Gregory palmas->dev = &i2c->dev; 2802945fbc2SGraeme Gregory palmas->irq = i2c->irq; 2812945fbc2SGraeme Gregory 2821ffb0be3SJ Keerthy match = of_match_device(of_match_ptr(of_palmas_match_tbl), &i2c->dev); 2831ffb0be3SJ Keerthy 2841ffb0be3SJ Keerthy if (!match) 2851ffb0be3SJ Keerthy return -ENODATA; 2861ffb0be3SJ Keerthy 2871ffb0be3SJ Keerthy features = (unsigned int *)match->data; 2881ffb0be3SJ Keerthy palmas->features = *features; 2891ffb0be3SJ Keerthy 2902945fbc2SGraeme Gregory for (i = 0; i < PALMAS_NUM_CLIENTS; i++) { 2912945fbc2SGraeme Gregory if (i == 0) 2922945fbc2SGraeme Gregory palmas->i2c_clients[i] = i2c; 2932945fbc2SGraeme Gregory else { 2942945fbc2SGraeme Gregory palmas->i2c_clients[i] = 2952945fbc2SGraeme Gregory i2c_new_dummy(i2c->adapter, 2962945fbc2SGraeme Gregory i2c->addr + i); 2972945fbc2SGraeme Gregory if (!palmas->i2c_clients[i]) { 2982945fbc2SGraeme Gregory dev_err(palmas->dev, 2992945fbc2SGraeme Gregory "can't attach client %d\n", i); 3002945fbc2SGraeme Gregory ret = -ENOMEM; 3012945fbc2SGraeme Gregory goto err; 3022945fbc2SGraeme Gregory } 303c4fbec3cSLaxman Dewangan palmas->i2c_clients[i]->dev.of_node = of_node_get(node); 3042945fbc2SGraeme Gregory } 3052945fbc2SGraeme Gregory palmas->regmap[i] = devm_regmap_init_i2c(palmas->i2c_clients[i], 3062945fbc2SGraeme Gregory &palmas_regmap_config[i]); 3072945fbc2SGraeme Gregory if (IS_ERR(palmas->regmap[i])) { 3082945fbc2SGraeme Gregory ret = PTR_ERR(palmas->regmap[i]); 3092945fbc2SGraeme Gregory dev_err(palmas->dev, 3102945fbc2SGraeme Gregory "Failed to allocate regmap %d, err: %d\n", 3112945fbc2SGraeme Gregory i, ret); 3122945fbc2SGraeme Gregory goto err; 3132945fbc2SGraeme Gregory } 3142945fbc2SGraeme Gregory } 3152945fbc2SGraeme Gregory 316ad522f4eSJ Keerthy if (!palmas->irq) { 317ad522f4eSJ Keerthy dev_warn(palmas->dev, "IRQ missing: skipping irq request\n"); 318ad522f4eSJ Keerthy goto no_irq; 319ad522f4eSJ Keerthy } 320ad522f4eSJ Keerthy 321df545d1cSLaxman Dewangan /* Change interrupt line output polarity */ 322df545d1cSLaxman Dewangan if (pdata->irq_flags & IRQ_TYPE_LEVEL_HIGH) 323df545d1cSLaxman Dewangan reg = PALMAS_POLARITY_CTRL_INT_POLARITY; 324df545d1cSLaxman Dewangan else 325df545d1cSLaxman Dewangan reg = 0; 326df545d1cSLaxman Dewangan ret = palmas_update_bits(palmas, PALMAS_PU_PD_OD_BASE, 327df545d1cSLaxman Dewangan PALMAS_POLARITY_CTRL, PALMAS_POLARITY_CTRL_INT_POLARITY, 328df545d1cSLaxman Dewangan reg); 329df545d1cSLaxman Dewangan if (ret < 0) { 330df545d1cSLaxman Dewangan dev_err(palmas->dev, "POLARITY_CTRL updat failed: %d\n", ret); 331df545d1cSLaxman Dewangan goto err; 332df545d1cSLaxman Dewangan } 333df545d1cSLaxman Dewangan 334b330f85dSGraeme Gregory /* Change IRQ into clear on read mode for efficiency */ 335b330f85dSGraeme Gregory slave = PALMAS_BASE_TO_SLAVE(PALMAS_INTERRUPT_BASE); 336b330f85dSGraeme Gregory addr = PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE, PALMAS_INT_CTRL); 337b330f85dSGraeme Gregory reg = PALMAS_INT_CTRL_INT_CLEAR; 338b330f85dSGraeme Gregory 339b330f85dSGraeme Gregory regmap_write(palmas->regmap[slave], addr, reg); 340b330f85dSGraeme Gregory 341b330f85dSGraeme Gregory ret = regmap_add_irq_chip(palmas->regmap[slave], palmas->irq, 342df545d1cSLaxman Dewangan IRQF_ONESHOT | pdata->irq_flags, 0, &palmas_irq_chip, 3432945fbc2SGraeme Gregory &palmas->irq_data); 3442945fbc2SGraeme Gregory if (ret < 0) 3452945fbc2SGraeme Gregory goto err; 3462945fbc2SGraeme Gregory 347ad522f4eSJ Keerthy no_irq: 3482945fbc2SGraeme Gregory slave = PALMAS_BASE_TO_SLAVE(PALMAS_PU_PD_OD_BASE); 3492945fbc2SGraeme Gregory addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE, 3502945fbc2SGraeme Gregory PALMAS_PRIMARY_SECONDARY_PAD1); 3512945fbc2SGraeme Gregory 3522945fbc2SGraeme Gregory if (pdata->mux_from_pdata) { 3532945fbc2SGraeme Gregory reg = pdata->pad1; 3542945fbc2SGraeme Gregory ret = regmap_write(palmas->regmap[slave], addr, reg); 3552945fbc2SGraeme Gregory if (ret) 3563f78deccSGraeme Gregory goto err_irq; 3572945fbc2SGraeme Gregory } else { 3582945fbc2SGraeme Gregory ret = regmap_read(palmas->regmap[slave], addr, ®); 3592945fbc2SGraeme Gregory if (ret) 3603f78deccSGraeme Gregory goto err_irq; 3612945fbc2SGraeme Gregory } 3622945fbc2SGraeme Gregory 3632945fbc2SGraeme Gregory if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_0)) 3642945fbc2SGraeme Gregory palmas->gpio_muxed |= PALMAS_GPIO_0_MUXED; 3652945fbc2SGraeme Gregory if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK)) 3662945fbc2SGraeme Gregory palmas->gpio_muxed |= PALMAS_GPIO_1_MUXED; 3672945fbc2SGraeme Gregory else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK) == 3682945fbc2SGraeme Gregory (2 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT)) 3692945fbc2SGraeme Gregory palmas->led_muxed |= PALMAS_LED1_MUXED; 3702945fbc2SGraeme Gregory else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK) == 3712945fbc2SGraeme Gregory (3 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT)) 3722945fbc2SGraeme Gregory palmas->pwm_muxed |= PALMAS_PWM1_MUXED; 3732945fbc2SGraeme Gregory if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK)) 3742945fbc2SGraeme Gregory palmas->gpio_muxed |= PALMAS_GPIO_2_MUXED; 3752945fbc2SGraeme Gregory else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK) == 3762945fbc2SGraeme Gregory (2 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT)) 3772945fbc2SGraeme Gregory palmas->led_muxed |= PALMAS_LED2_MUXED; 3782945fbc2SGraeme Gregory else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK) == 3792945fbc2SGraeme Gregory (3 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT)) 3802945fbc2SGraeme Gregory palmas->pwm_muxed |= PALMAS_PWM2_MUXED; 3812945fbc2SGraeme Gregory if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_3)) 3822945fbc2SGraeme Gregory palmas->gpio_muxed |= PALMAS_GPIO_3_MUXED; 3832945fbc2SGraeme Gregory 3842945fbc2SGraeme Gregory addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE, 3852945fbc2SGraeme Gregory PALMAS_PRIMARY_SECONDARY_PAD2); 3862945fbc2SGraeme Gregory 3872945fbc2SGraeme Gregory if (pdata->mux_from_pdata) { 3882945fbc2SGraeme Gregory reg = pdata->pad2; 3892945fbc2SGraeme Gregory ret = regmap_write(palmas->regmap[slave], addr, reg); 3902945fbc2SGraeme Gregory if (ret) 3913f78deccSGraeme Gregory goto err_irq; 3922945fbc2SGraeme Gregory } else { 3932945fbc2SGraeme Gregory ret = regmap_read(palmas->regmap[slave], addr, ®); 3942945fbc2SGraeme Gregory if (ret) 3953f78deccSGraeme Gregory goto err_irq; 3962945fbc2SGraeme Gregory } 3972945fbc2SGraeme Gregory 3982945fbc2SGraeme Gregory if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_4)) 3992945fbc2SGraeme Gregory palmas->gpio_muxed |= PALMAS_GPIO_4_MUXED; 4002945fbc2SGraeme Gregory if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_5_MASK)) 4012945fbc2SGraeme Gregory palmas->gpio_muxed |= PALMAS_GPIO_5_MUXED; 4022945fbc2SGraeme Gregory if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_6)) 4032945fbc2SGraeme Gregory palmas->gpio_muxed |= PALMAS_GPIO_6_MUXED; 4042945fbc2SGraeme Gregory if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_MASK)) 4052945fbc2SGraeme Gregory palmas->gpio_muxed |= PALMAS_GPIO_7_MUXED; 4062945fbc2SGraeme Gregory 4072945fbc2SGraeme Gregory dev_info(palmas->dev, "Muxing GPIO %x, PWM %x, LED %x\n", 4082945fbc2SGraeme Gregory palmas->gpio_muxed, palmas->pwm_muxed, 4092945fbc2SGraeme Gregory palmas->led_muxed); 4102945fbc2SGraeme Gregory 4112945fbc2SGraeme Gregory reg = pdata->power_ctrl; 4122945fbc2SGraeme Gregory 4132945fbc2SGraeme Gregory slave = PALMAS_BASE_TO_SLAVE(PALMAS_PMU_CONTROL_BASE); 4142945fbc2SGraeme Gregory addr = PALMAS_BASE_TO_REG(PALMAS_PMU_CONTROL_BASE, PALMAS_POWER_CTRL); 4152945fbc2SGraeme Gregory 4162945fbc2SGraeme Gregory ret = regmap_write(palmas->regmap[slave], addr, reg); 4172945fbc2SGraeme Gregory if (ret) 4183f78deccSGraeme Gregory goto err_irq; 4192945fbc2SGraeme Gregory 4209c14ac33SGraeme Gregory /* 4219c14ac33SGraeme Gregory * If we are probing with DT do this the DT way and return here 4229c14ac33SGraeme Gregory * otherwise continue and add devices using mfd helpers. 4239c14ac33SGraeme Gregory */ 4249c14ac33SGraeme Gregory if (node) { 4259c14ac33SGraeme Gregory ret = of_platform_populate(node, NULL, NULL, &i2c->dev); 4269c14ac33SGraeme Gregory if (ret < 0) 4279c14ac33SGraeme Gregory goto err_irq; 4289c14ac33SGraeme Gregory else 4299c14ac33SGraeme Gregory return ret; 4309c14ac33SGraeme Gregory } 4319c14ac33SGraeme Gregory 4322945fbc2SGraeme Gregory return ret; 4332945fbc2SGraeme Gregory 4343f78deccSGraeme Gregory err_irq: 4353f78deccSGraeme Gregory regmap_del_irq_chip(palmas->irq, palmas->irq_data); 4363f78deccSGraeme Gregory err: 4372945fbc2SGraeme Gregory return ret; 4382945fbc2SGraeme Gregory } 4392945fbc2SGraeme Gregory 4402945fbc2SGraeme Gregory static int palmas_i2c_remove(struct i2c_client *i2c) 4412945fbc2SGraeme Gregory { 4422945fbc2SGraeme Gregory struct palmas *palmas = i2c_get_clientdata(i2c); 4432945fbc2SGraeme Gregory 4442945fbc2SGraeme Gregory mfd_remove_devices(palmas->dev); 4452945fbc2SGraeme Gregory regmap_del_irq_chip(palmas->irq, palmas->irq_data); 4462945fbc2SGraeme Gregory 4472945fbc2SGraeme Gregory return 0; 4482945fbc2SGraeme Gregory } 4492945fbc2SGraeme Gregory 4502945fbc2SGraeme Gregory static const struct i2c_device_id palmas_i2c_id[] = { 4512945fbc2SGraeme Gregory { "palmas", }, 4522945fbc2SGraeme Gregory { "twl6035", }, 4532945fbc2SGraeme Gregory { "twl6037", }, 4542945fbc2SGraeme Gregory { "tps65913", }, 45500ba81c1SAxel Lin { /* end */ } 4562945fbc2SGraeme Gregory }; 4572945fbc2SGraeme Gregory MODULE_DEVICE_TABLE(i2c, palmas_i2c_id); 4582945fbc2SGraeme Gregory 4592945fbc2SGraeme Gregory static struct i2c_driver palmas_i2c_driver = { 4602945fbc2SGraeme Gregory .driver = { 4612945fbc2SGraeme Gregory .name = "palmas", 4622945fbc2SGraeme Gregory .of_match_table = of_palmas_match_tbl, 4632945fbc2SGraeme Gregory .owner = THIS_MODULE, 4642945fbc2SGraeme Gregory }, 4652945fbc2SGraeme Gregory .probe = palmas_i2c_probe, 4662945fbc2SGraeme Gregory .remove = palmas_i2c_remove, 4672945fbc2SGraeme Gregory .id_table = palmas_i2c_id, 4682945fbc2SGraeme Gregory }; 4692945fbc2SGraeme Gregory 4702945fbc2SGraeme Gregory static int __init palmas_i2c_init(void) 4712945fbc2SGraeme Gregory { 4722945fbc2SGraeme Gregory return i2c_add_driver(&palmas_i2c_driver); 4732945fbc2SGraeme Gregory } 4742945fbc2SGraeme Gregory /* init early so consumer devices can complete system boot */ 4752945fbc2SGraeme Gregory subsys_initcall(palmas_i2c_init); 4762945fbc2SGraeme Gregory 4772945fbc2SGraeme Gregory static void __exit palmas_i2c_exit(void) 4782945fbc2SGraeme Gregory { 4792945fbc2SGraeme Gregory i2c_del_driver(&palmas_i2c_driver); 4802945fbc2SGraeme Gregory } 4812945fbc2SGraeme Gregory module_exit(palmas_i2c_exit); 4822945fbc2SGraeme Gregory 4832945fbc2SGraeme Gregory MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>"); 4842945fbc2SGraeme Gregory MODULE_DESCRIPTION("Palmas chip family multi-function driver"); 4852945fbc2SGraeme Gregory MODULE_LICENSE("GPL"); 486