18e685483SKrystian Garbaciak /* da9063-i2c.c: Interrupt support for Dialog DA9063 28e685483SKrystian Garbaciak * 38e685483SKrystian Garbaciak * Copyright 2012 Dialog Semiconductor Ltd. 48e685483SKrystian Garbaciak * Copyright 2013 Philipp Zabel, Pengutronix 58e685483SKrystian Garbaciak * 68e685483SKrystian Garbaciak * Author: Krystian Garbaciak <krystian.garbaciak@diasemi.com> 78e685483SKrystian Garbaciak * 88e685483SKrystian Garbaciak * This program is free software; you can redistribute it and/or modify it 98e685483SKrystian Garbaciak * under the terms of the GNU General Public License as published by the 108e685483SKrystian Garbaciak * Free Software Foundation; either version 2 of the License, or (at your 118e685483SKrystian Garbaciak * option) any later version. 128e685483SKrystian Garbaciak * 138e685483SKrystian Garbaciak */ 148e685483SKrystian Garbaciak 158e685483SKrystian Garbaciak #include <linux/kernel.h> 168e685483SKrystian Garbaciak #include <linux/module.h> 178e685483SKrystian Garbaciak #include <linux/i2c.h> 188e685483SKrystian Garbaciak #include <linux/regmap.h> 198e685483SKrystian Garbaciak #include <linux/delay.h> 208e685483SKrystian Garbaciak #include <linux/slab.h> 218e685483SKrystian Garbaciak #include <linux/err.h> 228e685483SKrystian Garbaciak 238e685483SKrystian Garbaciak #include <linux/mfd/core.h> 248e685483SKrystian Garbaciak #include <linux/mfd/da9063/core.h> 258e685483SKrystian Garbaciak #include <linux/mfd/da9063/pdata.h> 268e685483SKrystian Garbaciak #include <linux/mfd/da9063/registers.h> 278e685483SKrystian Garbaciak 2871e03de4SSteve Twiss #include <linux/of.h> 2971e03de4SSteve Twiss #include <linux/regulator/of_regulator.h> 3071e03de4SSteve Twiss 319cb42e2aSOpensource [Steve Twiss] static const struct regmap_range da9063_ad_readable_ranges[] = { 328e685483SKrystian Garbaciak { 338e685483SKrystian Garbaciak .range_min = DA9063_REG_PAGE_CON, 349cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_AD_REG_SECOND_D, 358e685483SKrystian Garbaciak }, { 368e685483SKrystian Garbaciak .range_min = DA9063_REG_SEQ, 378e685483SKrystian Garbaciak .range_max = DA9063_REG_ID_32_31, 388e685483SKrystian Garbaciak }, { 398e685483SKrystian Garbaciak .range_min = DA9063_REG_SEQ_A, 408e685483SKrystian Garbaciak .range_max = DA9063_REG_AUTO3_LOW, 418e685483SKrystian Garbaciak }, { 428e685483SKrystian Garbaciak .range_min = DA9063_REG_T_OFFSET, 439cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_AD_REG_GP_ID_19, 448e685483SKrystian Garbaciak }, { 458e685483SKrystian Garbaciak .range_min = DA9063_REG_CHIP_ID, 468e685483SKrystian Garbaciak .range_max = DA9063_REG_CHIP_VARIANT, 478e685483SKrystian Garbaciak }, 488e685483SKrystian Garbaciak }; 498e685483SKrystian Garbaciak 509cb42e2aSOpensource [Steve Twiss] static const struct regmap_range da9063_ad_writeable_ranges[] = { 518e685483SKrystian Garbaciak { 528e685483SKrystian Garbaciak .range_min = DA9063_REG_PAGE_CON, 538e685483SKrystian Garbaciak .range_max = DA9063_REG_PAGE_CON, 548e685483SKrystian Garbaciak }, { 558e685483SKrystian Garbaciak .range_min = DA9063_REG_FAULT_LOG, 568e685483SKrystian Garbaciak .range_max = DA9063_REG_VSYS_MON, 578e685483SKrystian Garbaciak }, { 588e685483SKrystian Garbaciak .range_min = DA9063_REG_COUNT_S, 599cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_AD_REG_ALARM_Y, 608e685483SKrystian Garbaciak }, { 618e685483SKrystian Garbaciak .range_min = DA9063_REG_SEQ, 628e685483SKrystian Garbaciak .range_max = DA9063_REG_ID_32_31, 638e685483SKrystian Garbaciak }, { 648e685483SKrystian Garbaciak .range_min = DA9063_REG_SEQ_A, 658e685483SKrystian Garbaciak .range_max = DA9063_REG_AUTO3_LOW, 668e685483SKrystian Garbaciak }, { 678e685483SKrystian Garbaciak .range_min = DA9063_REG_CONFIG_I, 689cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_AD_REG_MON_REG_4, 698e685483SKrystian Garbaciak }, { 709cb42e2aSOpensource [Steve Twiss] .range_min = DA9063_AD_REG_GP_ID_0, 719cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_AD_REG_GP_ID_19, 728e685483SKrystian Garbaciak }, 738e685483SKrystian Garbaciak }; 748e685483SKrystian Garbaciak 759cb42e2aSOpensource [Steve Twiss] static const struct regmap_range da9063_ad_volatile_ranges[] = { 768e685483SKrystian Garbaciak { 778e685483SKrystian Garbaciak .range_min = DA9063_REG_STATUS_A, 788e685483SKrystian Garbaciak .range_max = DA9063_REG_EVENT_D, 798e685483SKrystian Garbaciak }, { 808e685483SKrystian Garbaciak .range_min = DA9063_REG_CONTROL_F, 818e685483SKrystian Garbaciak .range_max = DA9063_REG_CONTROL_F, 828e685483SKrystian Garbaciak }, { 838e685483SKrystian Garbaciak .range_min = DA9063_REG_ADC_MAN, 848e685483SKrystian Garbaciak .range_max = DA9063_REG_ADC_MAN, 858e685483SKrystian Garbaciak }, { 868e685483SKrystian Garbaciak .range_min = DA9063_REG_ADC_RES_L, 879cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_AD_REG_SECOND_D, 888e685483SKrystian Garbaciak }, { 899cb42e2aSOpensource [Steve Twiss] .range_min = DA9063_AD_REG_MON_REG_5, 909cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_AD_REG_MON_REG_6, 918e685483SKrystian Garbaciak }, 928e685483SKrystian Garbaciak }; 938e685483SKrystian Garbaciak 949cb42e2aSOpensource [Steve Twiss] static const struct regmap_access_table da9063_ad_readable_table = { 959cb42e2aSOpensource [Steve Twiss] .yes_ranges = da9063_ad_readable_ranges, 969cb42e2aSOpensource [Steve Twiss] .n_yes_ranges = ARRAY_SIZE(da9063_ad_readable_ranges), 978e685483SKrystian Garbaciak }; 988e685483SKrystian Garbaciak 999cb42e2aSOpensource [Steve Twiss] static const struct regmap_access_table da9063_ad_writeable_table = { 1009cb42e2aSOpensource [Steve Twiss] .yes_ranges = da9063_ad_writeable_ranges, 1019cb42e2aSOpensource [Steve Twiss] .n_yes_ranges = ARRAY_SIZE(da9063_ad_writeable_ranges), 1028e685483SKrystian Garbaciak }; 1038e685483SKrystian Garbaciak 1049cb42e2aSOpensource [Steve Twiss] static const struct regmap_access_table da9063_ad_volatile_table = { 1059cb42e2aSOpensource [Steve Twiss] .yes_ranges = da9063_ad_volatile_ranges, 1069cb42e2aSOpensource [Steve Twiss] .n_yes_ranges = ARRAY_SIZE(da9063_ad_volatile_ranges), 1079cb42e2aSOpensource [Steve Twiss] }; 1089cb42e2aSOpensource [Steve Twiss] 1099cb42e2aSOpensource [Steve Twiss] static const struct regmap_range da9063_bb_readable_ranges[] = { 1109cb42e2aSOpensource [Steve Twiss] { 1119cb42e2aSOpensource [Steve Twiss] .range_min = DA9063_REG_PAGE_CON, 1129cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_BB_REG_SECOND_D, 1139cb42e2aSOpensource [Steve Twiss] }, { 1149cb42e2aSOpensource [Steve Twiss] .range_min = DA9063_REG_SEQ, 1159cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_REG_ID_32_31, 1169cb42e2aSOpensource [Steve Twiss] }, { 1179cb42e2aSOpensource [Steve Twiss] .range_min = DA9063_REG_SEQ_A, 1189cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_REG_AUTO3_LOW, 1199cb42e2aSOpensource [Steve Twiss] }, { 1209cb42e2aSOpensource [Steve Twiss] .range_min = DA9063_REG_T_OFFSET, 1219cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_BB_REG_GP_ID_19, 1229cb42e2aSOpensource [Steve Twiss] }, { 1239cb42e2aSOpensource [Steve Twiss] .range_min = DA9063_REG_CHIP_ID, 1249cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_REG_CHIP_VARIANT, 1259cb42e2aSOpensource [Steve Twiss] }, 1269cb42e2aSOpensource [Steve Twiss] }; 1279cb42e2aSOpensource [Steve Twiss] 1289cb42e2aSOpensource [Steve Twiss] static const struct regmap_range da9063_bb_writeable_ranges[] = { 1299cb42e2aSOpensource [Steve Twiss] { 1309cb42e2aSOpensource [Steve Twiss] .range_min = DA9063_REG_PAGE_CON, 1319cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_REG_PAGE_CON, 1329cb42e2aSOpensource [Steve Twiss] }, { 1339cb42e2aSOpensource [Steve Twiss] .range_min = DA9063_REG_FAULT_LOG, 1349cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_REG_VSYS_MON, 1359cb42e2aSOpensource [Steve Twiss] }, { 1369cb42e2aSOpensource [Steve Twiss] .range_min = DA9063_REG_COUNT_S, 1379cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_BB_REG_ALARM_Y, 1389cb42e2aSOpensource [Steve Twiss] }, { 1399cb42e2aSOpensource [Steve Twiss] .range_min = DA9063_REG_SEQ, 1409cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_REG_ID_32_31, 1419cb42e2aSOpensource [Steve Twiss] }, { 1429cb42e2aSOpensource [Steve Twiss] .range_min = DA9063_REG_SEQ_A, 1439cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_REG_AUTO3_LOW, 1449cb42e2aSOpensource [Steve Twiss] }, { 1459cb42e2aSOpensource [Steve Twiss] .range_min = DA9063_REG_CONFIG_I, 1469cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_BB_REG_MON_REG_4, 1479cb42e2aSOpensource [Steve Twiss] }, { 1489cb42e2aSOpensource [Steve Twiss] .range_min = DA9063_BB_REG_GP_ID_0, 1499cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_BB_REG_GP_ID_19, 1509cb42e2aSOpensource [Steve Twiss] }, 1519cb42e2aSOpensource [Steve Twiss] }; 1529cb42e2aSOpensource [Steve Twiss] 1539cb42e2aSOpensource [Steve Twiss] static const struct regmap_range da9063_bb_volatile_ranges[] = { 1549cb42e2aSOpensource [Steve Twiss] { 1559cb42e2aSOpensource [Steve Twiss] .range_min = DA9063_REG_STATUS_A, 1569cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_REG_EVENT_D, 1579cb42e2aSOpensource [Steve Twiss] }, { 1589cb42e2aSOpensource [Steve Twiss] .range_min = DA9063_REG_CONTROL_F, 1599cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_REG_CONTROL_F, 1609cb42e2aSOpensource [Steve Twiss] }, { 1619cb42e2aSOpensource [Steve Twiss] .range_min = DA9063_REG_ADC_MAN, 1629cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_REG_ADC_MAN, 1639cb42e2aSOpensource [Steve Twiss] }, { 1649cb42e2aSOpensource [Steve Twiss] .range_min = DA9063_REG_ADC_RES_L, 1659cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_BB_REG_SECOND_D, 1669cb42e2aSOpensource [Steve Twiss] }, { 1679cb42e2aSOpensource [Steve Twiss] .range_min = DA9063_BB_REG_MON_REG_5, 1689cb42e2aSOpensource [Steve Twiss] .range_max = DA9063_BB_REG_MON_REG_6, 1699cb42e2aSOpensource [Steve Twiss] }, 1709cb42e2aSOpensource [Steve Twiss] }; 1719cb42e2aSOpensource [Steve Twiss] 1729cb42e2aSOpensource [Steve Twiss] static const struct regmap_access_table da9063_bb_readable_table = { 1739cb42e2aSOpensource [Steve Twiss] .yes_ranges = da9063_bb_readable_ranges, 1749cb42e2aSOpensource [Steve Twiss] .n_yes_ranges = ARRAY_SIZE(da9063_bb_readable_ranges), 1759cb42e2aSOpensource [Steve Twiss] }; 1769cb42e2aSOpensource [Steve Twiss] 1779cb42e2aSOpensource [Steve Twiss] static const struct regmap_access_table da9063_bb_writeable_table = { 1789cb42e2aSOpensource [Steve Twiss] .yes_ranges = da9063_bb_writeable_ranges, 1799cb42e2aSOpensource [Steve Twiss] .n_yes_ranges = ARRAY_SIZE(da9063_bb_writeable_ranges), 1809cb42e2aSOpensource [Steve Twiss] }; 1819cb42e2aSOpensource [Steve Twiss] 1829cb42e2aSOpensource [Steve Twiss] static const struct regmap_access_table da9063_bb_volatile_table = { 1839cb42e2aSOpensource [Steve Twiss] .yes_ranges = da9063_bb_volatile_ranges, 1849cb42e2aSOpensource [Steve Twiss] .n_yes_ranges = ARRAY_SIZE(da9063_bb_volatile_ranges), 1858e685483SKrystian Garbaciak }; 1868e685483SKrystian Garbaciak 1878e685483SKrystian Garbaciak static const struct regmap_range_cfg da9063_range_cfg[] = { 1888e685483SKrystian Garbaciak { 1898e685483SKrystian Garbaciak .range_min = DA9063_REG_PAGE_CON, 1908e685483SKrystian Garbaciak .range_max = DA9063_REG_CHIP_VARIANT, 1918e685483SKrystian Garbaciak .selector_reg = DA9063_REG_PAGE_CON, 1928e685483SKrystian Garbaciak .selector_mask = 1 << DA9063_I2C_PAGE_SEL_SHIFT, 1938e685483SKrystian Garbaciak .selector_shift = DA9063_I2C_PAGE_SEL_SHIFT, 1948e685483SKrystian Garbaciak .window_start = 0, 1958e685483SKrystian Garbaciak .window_len = 256, 1968e685483SKrystian Garbaciak } 1978e685483SKrystian Garbaciak }; 1988e685483SKrystian Garbaciak 1998e685483SKrystian Garbaciak static struct regmap_config da9063_regmap_config = { 2008e685483SKrystian Garbaciak .reg_bits = 8, 2018e685483SKrystian Garbaciak .val_bits = 8, 2028e685483SKrystian Garbaciak .ranges = da9063_range_cfg, 2038e685483SKrystian Garbaciak .num_ranges = ARRAY_SIZE(da9063_range_cfg), 2048e685483SKrystian Garbaciak .max_register = DA9063_REG_CHIP_VARIANT, 2058e685483SKrystian Garbaciak 2068e685483SKrystian Garbaciak .cache_type = REGCACHE_RBTREE, 2078e685483SKrystian Garbaciak }; 2088e685483SKrystian Garbaciak 20971e03de4SSteve Twiss static const struct of_device_id da9063_dt_ids[] = { 21071e03de4SSteve Twiss { .compatible = "dlg,da9063", }, 21171e03de4SSteve Twiss { } 21271e03de4SSteve Twiss }; 21371e03de4SSteve Twiss MODULE_DEVICE_TABLE(of, da9063_dt_ids); 2148e685483SKrystian Garbaciak static int da9063_i2c_probe(struct i2c_client *i2c, 2158e685483SKrystian Garbaciak const struct i2c_device_id *id) 2168e685483SKrystian Garbaciak { 2178e685483SKrystian Garbaciak struct da9063 *da9063; 2188e685483SKrystian Garbaciak int ret; 2198e685483SKrystian Garbaciak 2208e685483SKrystian Garbaciak da9063 = devm_kzalloc(&i2c->dev, sizeof(struct da9063), GFP_KERNEL); 2218e685483SKrystian Garbaciak if (da9063 == NULL) 2228e685483SKrystian Garbaciak return -ENOMEM; 2238e685483SKrystian Garbaciak 2248e685483SKrystian Garbaciak i2c_set_clientdata(i2c, da9063); 2258e685483SKrystian Garbaciak da9063->dev = &i2c->dev; 2268e685483SKrystian Garbaciak da9063->chip_irq = i2c->irq; 2278e685483SKrystian Garbaciak 2289cb42e2aSOpensource [Steve Twiss] if (da9063->variant_code == PMIC_DA9063_AD) { 2299cb42e2aSOpensource [Steve Twiss] da9063_regmap_config.rd_table = &da9063_ad_readable_table; 2309cb42e2aSOpensource [Steve Twiss] da9063_regmap_config.wr_table = &da9063_ad_writeable_table; 2319cb42e2aSOpensource [Steve Twiss] da9063_regmap_config.volatile_table = &da9063_ad_volatile_table; 2329cb42e2aSOpensource [Steve Twiss] } else { 2339cb42e2aSOpensource [Steve Twiss] da9063_regmap_config.rd_table = &da9063_bb_readable_table; 2349cb42e2aSOpensource [Steve Twiss] da9063_regmap_config.wr_table = &da9063_bb_writeable_table; 2359cb42e2aSOpensource [Steve Twiss] da9063_regmap_config.volatile_table = &da9063_bb_volatile_table; 2369cb42e2aSOpensource [Steve Twiss] } 2379cb42e2aSOpensource [Steve Twiss] 2388e685483SKrystian Garbaciak da9063->regmap = devm_regmap_init_i2c(i2c, &da9063_regmap_config); 2398e685483SKrystian Garbaciak if (IS_ERR(da9063->regmap)) { 2408e685483SKrystian Garbaciak ret = PTR_ERR(da9063->regmap); 2418e685483SKrystian Garbaciak dev_err(da9063->dev, "Failed to allocate register map: %d\n", 2428e685483SKrystian Garbaciak ret); 2438e685483SKrystian Garbaciak return ret; 2448e685483SKrystian Garbaciak } 2458e685483SKrystian Garbaciak 2468e685483SKrystian Garbaciak return da9063_device_init(da9063, i2c->irq); 2478e685483SKrystian Garbaciak } 2488e685483SKrystian Garbaciak 2498e685483SKrystian Garbaciak static int da9063_i2c_remove(struct i2c_client *i2c) 2508e685483SKrystian Garbaciak { 2518e685483SKrystian Garbaciak struct da9063 *da9063 = i2c_get_clientdata(i2c); 2528e685483SKrystian Garbaciak 2538e685483SKrystian Garbaciak da9063_device_exit(da9063); 2548e685483SKrystian Garbaciak 2558e685483SKrystian Garbaciak return 0; 2568e685483SKrystian Garbaciak } 2578e685483SKrystian Garbaciak 2588e685483SKrystian Garbaciak static const struct i2c_device_id da9063_i2c_id[] = { 2598e685483SKrystian Garbaciak {"da9063", PMIC_DA9063}, 2608e685483SKrystian Garbaciak {}, 2618e685483SKrystian Garbaciak }; 2628e685483SKrystian Garbaciak MODULE_DEVICE_TABLE(i2c, da9063_i2c_id); 2638e685483SKrystian Garbaciak 2648e685483SKrystian Garbaciak static struct i2c_driver da9063_i2c_driver = { 2658e685483SKrystian Garbaciak .driver = { 2668e685483SKrystian Garbaciak .name = "da9063", 2678e685483SKrystian Garbaciak .owner = THIS_MODULE, 26871e03de4SSteve Twiss .of_match_table = of_match_ptr(da9063_dt_ids), 2698e685483SKrystian Garbaciak }, 2708e685483SKrystian Garbaciak .probe = da9063_i2c_probe, 2718e685483SKrystian Garbaciak .remove = da9063_i2c_remove, 2728e685483SKrystian Garbaciak .id_table = da9063_i2c_id, 2738e685483SKrystian Garbaciak }; 2748e685483SKrystian Garbaciak 2758e685483SKrystian Garbaciak module_i2c_driver(da9063_i2c_driver); 276