19efbc6f1SWolfram Sang // SPDX-License-Identifier: GPL-2.0+
29efbc6f1SWolfram Sang /* I2C support for Dialog DA9063
38e685483SKrystian Garbaciak *
48e685483SKrystian Garbaciak * Copyright 2012 Dialog Semiconductor Ltd.
58e685483SKrystian Garbaciak * Copyright 2013 Philipp Zabel, Pengutronix
68e685483SKrystian Garbaciak *
737778d83SSteve Twiss * Author: Krystian Garbaciak, Dialog Semiconductor
88e685483SKrystian Garbaciak */
98e685483SKrystian Garbaciak
108e685483SKrystian Garbaciak #include <linux/kernel.h>
118e685483SKrystian Garbaciak #include <linux/module.h>
128e685483SKrystian Garbaciak #include <linux/i2c.h>
138e685483SKrystian Garbaciak #include <linux/regmap.h>
148e685483SKrystian Garbaciak #include <linux/delay.h>
158e685483SKrystian Garbaciak #include <linux/slab.h>
168e685483SKrystian Garbaciak #include <linux/err.h>
178e685483SKrystian Garbaciak
188e685483SKrystian Garbaciak #include <linux/mfd/core.h>
198e685483SKrystian Garbaciak #include <linux/mfd/da9063/core.h>
208e685483SKrystian Garbaciak #include <linux/mfd/da9063/registers.h>
218e685483SKrystian Garbaciak
2271e03de4SSteve Twiss #include <linux/of.h>
2371e03de4SSteve Twiss #include <linux/regulator/of_regulator.h>
2471e03de4SSteve Twiss
25091c6110SAdam Thomson /*
26091c6110SAdam Thomson * Raw I2C access required for just accessing chip and variant info before we
27091c6110SAdam Thomson * know which device is present. The info read from the device using this
28091c6110SAdam Thomson * approach is then used to select the correct regmap tables.
29091c6110SAdam Thomson */
30091c6110SAdam Thomson
31091c6110SAdam Thomson #define DA9063_REG_PAGE_SIZE 0x100
32091c6110SAdam Thomson #define DA9063_REG_PAGED_ADDR_MASK 0xFF
33091c6110SAdam Thomson
34091c6110SAdam Thomson enum da9063_page_sel_buf_fmt {
35091c6110SAdam Thomson DA9063_PAGE_SEL_BUF_PAGE_REG = 0,
36091c6110SAdam Thomson DA9063_PAGE_SEL_BUF_PAGE_VAL,
37091c6110SAdam Thomson DA9063_PAGE_SEL_BUF_SIZE,
38091c6110SAdam Thomson };
39091c6110SAdam Thomson
40091c6110SAdam Thomson enum da9063_paged_read_msgs {
41091c6110SAdam Thomson DA9063_PAGED_READ_MSG_PAGE_SEL = 0,
42091c6110SAdam Thomson DA9063_PAGED_READ_MSG_REG_SEL,
43091c6110SAdam Thomson DA9063_PAGED_READ_MSG_DATA,
44091c6110SAdam Thomson DA9063_PAGED_READ_MSG_CNT,
45091c6110SAdam Thomson };
46091c6110SAdam Thomson
da9063_i2c_blockreg_read(struct i2c_client * client,u16 addr,u8 * buf,int count)47091c6110SAdam Thomson static int da9063_i2c_blockreg_read(struct i2c_client *client, u16 addr,
48091c6110SAdam Thomson u8 *buf, int count)
49091c6110SAdam Thomson {
50091c6110SAdam Thomson struct i2c_msg xfer[DA9063_PAGED_READ_MSG_CNT];
51091c6110SAdam Thomson u8 page_sel_buf[DA9063_PAGE_SEL_BUF_SIZE];
52091c6110SAdam Thomson u8 page_num, paged_addr;
53091c6110SAdam Thomson int ret;
54091c6110SAdam Thomson
55091c6110SAdam Thomson /* Determine page info based on register address */
56091c6110SAdam Thomson page_num = (addr / DA9063_REG_PAGE_SIZE);
57091c6110SAdam Thomson if (page_num > 1) {
58091c6110SAdam Thomson dev_err(&client->dev, "Invalid register address provided\n");
59091c6110SAdam Thomson return -EINVAL;
60091c6110SAdam Thomson }
61091c6110SAdam Thomson
62091c6110SAdam Thomson paged_addr = (addr % DA9063_REG_PAGE_SIZE) & DA9063_REG_PAGED_ADDR_MASK;
63091c6110SAdam Thomson page_sel_buf[DA9063_PAGE_SEL_BUF_PAGE_REG] = DA9063_REG_PAGE_CON;
64091c6110SAdam Thomson page_sel_buf[DA9063_PAGE_SEL_BUF_PAGE_VAL] =
65091c6110SAdam Thomson (page_num << DA9063_I2C_PAGE_SEL_SHIFT) & DA9063_REG_PAGE_MASK;
66091c6110SAdam Thomson
67091c6110SAdam Thomson /* Write reg address, page selection */
68091c6110SAdam Thomson xfer[DA9063_PAGED_READ_MSG_PAGE_SEL].addr = client->addr;
69091c6110SAdam Thomson xfer[DA9063_PAGED_READ_MSG_PAGE_SEL].flags = 0;
70091c6110SAdam Thomson xfer[DA9063_PAGED_READ_MSG_PAGE_SEL].len = DA9063_PAGE_SEL_BUF_SIZE;
71091c6110SAdam Thomson xfer[DA9063_PAGED_READ_MSG_PAGE_SEL].buf = page_sel_buf;
72091c6110SAdam Thomson
73091c6110SAdam Thomson /* Select register address */
74091c6110SAdam Thomson xfer[DA9063_PAGED_READ_MSG_REG_SEL].addr = client->addr;
75091c6110SAdam Thomson xfer[DA9063_PAGED_READ_MSG_REG_SEL].flags = 0;
76091c6110SAdam Thomson xfer[DA9063_PAGED_READ_MSG_REG_SEL].len = sizeof(paged_addr);
77091c6110SAdam Thomson xfer[DA9063_PAGED_READ_MSG_REG_SEL].buf = &paged_addr;
78091c6110SAdam Thomson
79091c6110SAdam Thomson /* Read data */
80091c6110SAdam Thomson xfer[DA9063_PAGED_READ_MSG_DATA].addr = client->addr;
81091c6110SAdam Thomson xfer[DA9063_PAGED_READ_MSG_DATA].flags = I2C_M_RD;
82091c6110SAdam Thomson xfer[DA9063_PAGED_READ_MSG_DATA].len = count;
83091c6110SAdam Thomson xfer[DA9063_PAGED_READ_MSG_DATA].buf = buf;
84091c6110SAdam Thomson
85091c6110SAdam Thomson ret = i2c_transfer(client->adapter, xfer, DA9063_PAGED_READ_MSG_CNT);
86091c6110SAdam Thomson if (ret < 0) {
87091c6110SAdam Thomson dev_err(&client->dev, "Paged block read failed: %d\n", ret);
88091c6110SAdam Thomson return ret;
89091c6110SAdam Thomson }
90091c6110SAdam Thomson
91091c6110SAdam Thomson if (ret != DA9063_PAGED_READ_MSG_CNT) {
92091c6110SAdam Thomson dev_err(&client->dev, "Paged block read failed to complete\n");
93091c6110SAdam Thomson return -EIO;
94091c6110SAdam Thomson }
95091c6110SAdam Thomson
96091c6110SAdam Thomson return 0;
97091c6110SAdam Thomson }
98091c6110SAdam Thomson
99091c6110SAdam Thomson enum {
100091c6110SAdam Thomson DA9063_DEV_ID_REG = 0,
101091c6110SAdam Thomson DA9063_VAR_ID_REG,
102091c6110SAdam Thomson DA9063_CHIP_ID_REGS,
103091c6110SAdam Thomson };
104091c6110SAdam Thomson
da9063_get_device_type(struct i2c_client * i2c,struct da9063 * da9063)105091c6110SAdam Thomson static int da9063_get_device_type(struct i2c_client *i2c, struct da9063 *da9063)
106091c6110SAdam Thomson {
107091c6110SAdam Thomson u8 buf[DA9063_CHIP_ID_REGS];
108091c6110SAdam Thomson int ret;
109091c6110SAdam Thomson
110091c6110SAdam Thomson ret = da9063_i2c_blockreg_read(i2c, DA9063_REG_DEVICE_ID, buf,
111091c6110SAdam Thomson DA9063_CHIP_ID_REGS);
112091c6110SAdam Thomson if (ret)
113091c6110SAdam Thomson return ret;
114091c6110SAdam Thomson
115091c6110SAdam Thomson if (buf[DA9063_DEV_ID_REG] != PMIC_CHIP_ID_DA9063) {
116091c6110SAdam Thomson dev_err(da9063->dev,
117091c6110SAdam Thomson "Invalid chip device ID: 0x%02x\n",
118091c6110SAdam Thomson buf[DA9063_DEV_ID_REG]);
119091c6110SAdam Thomson return -ENODEV;
120091c6110SAdam Thomson }
121091c6110SAdam Thomson
122091c6110SAdam Thomson dev_info(da9063->dev,
123091c6110SAdam Thomson "Device detected (chip-ID: 0x%02X, var-ID: 0x%02X)\n",
124091c6110SAdam Thomson buf[DA9063_DEV_ID_REG], buf[DA9063_VAR_ID_REG]);
125091c6110SAdam Thomson
126091c6110SAdam Thomson da9063->variant_code =
127091c6110SAdam Thomson (buf[DA9063_VAR_ID_REG] & DA9063_VARIANT_ID_MRC_MASK)
128091c6110SAdam Thomson >> DA9063_VARIANT_ID_MRC_SHIFT;
129091c6110SAdam Thomson
130091c6110SAdam Thomson return 0;
131091c6110SAdam Thomson }
132091c6110SAdam Thomson
133091c6110SAdam Thomson /*
134091c6110SAdam Thomson * Variant specific regmap configs
135091c6110SAdam Thomson */
136091c6110SAdam Thomson
1379cb42e2aSOpensource [Steve Twiss] static const struct regmap_range da9063_ad_readable_ranges[] = {
1382905086dSMarek Vasut regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_AD_REG_SECOND_D),
1392905086dSMarek Vasut regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31),
1402905086dSMarek Vasut regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW),
1412905086dSMarek Vasut regmap_reg_range(DA9063_REG_T_OFFSET, DA9063_AD_REG_GP_ID_19),
142091c6110SAdam Thomson regmap_reg_range(DA9063_REG_DEVICE_ID, DA9063_REG_VARIANT_ID),
1438e685483SKrystian Garbaciak };
1448e685483SKrystian Garbaciak
1459cb42e2aSOpensource [Steve Twiss] static const struct regmap_range da9063_ad_writeable_ranges[] = {
1462905086dSMarek Vasut regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_PAGE_CON),
1472905086dSMarek Vasut regmap_reg_range(DA9063_REG_FAULT_LOG, DA9063_REG_VSYS_MON),
1482905086dSMarek Vasut regmap_reg_range(DA9063_REG_COUNT_S, DA9063_AD_REG_ALARM_Y),
1492905086dSMarek Vasut regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31),
1502905086dSMarek Vasut regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW),
1512905086dSMarek Vasut regmap_reg_range(DA9063_REG_CONFIG_I, DA9063_AD_REG_MON_REG_4),
1522905086dSMarek Vasut regmap_reg_range(DA9063_AD_REG_GP_ID_0, DA9063_AD_REG_GP_ID_19),
1538e685483SKrystian Garbaciak };
1548e685483SKrystian Garbaciak
1559cb42e2aSOpensource [Steve Twiss] static const struct regmap_range da9063_ad_volatile_ranges[] = {
1562905086dSMarek Vasut regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_EVENT_D),
1572905086dSMarek Vasut regmap_reg_range(DA9063_REG_CONTROL_A, DA9063_REG_CONTROL_B),
1582905086dSMarek Vasut regmap_reg_range(DA9063_REG_CONTROL_E, DA9063_REG_CONTROL_F),
1592905086dSMarek Vasut regmap_reg_range(DA9063_REG_BCORE2_CONT, DA9063_REG_LDO11_CONT),
1602905086dSMarek Vasut regmap_reg_range(DA9063_REG_DVC_1, DA9063_REG_ADC_MAN),
1612905086dSMarek Vasut regmap_reg_range(DA9063_REG_ADC_RES_L, DA9063_AD_REG_SECOND_D),
1622905086dSMarek Vasut regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_SEQ),
1632905086dSMarek Vasut regmap_reg_range(DA9063_REG_EN_32K, DA9063_REG_EN_32K),
1642905086dSMarek Vasut regmap_reg_range(DA9063_AD_REG_MON_REG_5, DA9063_AD_REG_MON_REG_6),
1658e685483SKrystian Garbaciak };
1668e685483SKrystian Garbaciak
1679cb42e2aSOpensource [Steve Twiss] static const struct regmap_access_table da9063_ad_readable_table = {
1689cb42e2aSOpensource [Steve Twiss] .yes_ranges = da9063_ad_readable_ranges,
1699cb42e2aSOpensource [Steve Twiss] .n_yes_ranges = ARRAY_SIZE(da9063_ad_readable_ranges),
1708e685483SKrystian Garbaciak };
1718e685483SKrystian Garbaciak
1729cb42e2aSOpensource [Steve Twiss] static const struct regmap_access_table da9063_ad_writeable_table = {
1739cb42e2aSOpensource [Steve Twiss] .yes_ranges = da9063_ad_writeable_ranges,
1749cb42e2aSOpensource [Steve Twiss] .n_yes_ranges = ARRAY_SIZE(da9063_ad_writeable_ranges),
1758e685483SKrystian Garbaciak };
1768e685483SKrystian Garbaciak
1779cb42e2aSOpensource [Steve Twiss] static const struct regmap_access_table da9063_ad_volatile_table = {
1789cb42e2aSOpensource [Steve Twiss] .yes_ranges = da9063_ad_volatile_ranges,
1799cb42e2aSOpensource [Steve Twiss] .n_yes_ranges = ARRAY_SIZE(da9063_ad_volatile_ranges),
1809cb42e2aSOpensource [Steve Twiss] };
1819cb42e2aSOpensource [Steve Twiss]
1829cb42e2aSOpensource [Steve Twiss] static const struct regmap_range da9063_bb_readable_ranges[] = {
1832905086dSMarek Vasut regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_BB_REG_SECOND_D),
1842905086dSMarek Vasut regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31),
1852905086dSMarek Vasut regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW),
1862905086dSMarek Vasut regmap_reg_range(DA9063_REG_T_OFFSET, DA9063_BB_REG_GP_ID_19),
187091c6110SAdam Thomson regmap_reg_range(DA9063_REG_DEVICE_ID, DA9063_REG_VARIANT_ID),
1889cb42e2aSOpensource [Steve Twiss] };
1899cb42e2aSOpensource [Steve Twiss]
1909cb42e2aSOpensource [Steve Twiss] static const struct regmap_range da9063_bb_writeable_ranges[] = {
1912905086dSMarek Vasut regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_PAGE_CON),
1922905086dSMarek Vasut regmap_reg_range(DA9063_REG_FAULT_LOG, DA9063_REG_VSYS_MON),
1932905086dSMarek Vasut regmap_reg_range(DA9063_REG_COUNT_S, DA9063_BB_REG_ALARM_Y),
1942905086dSMarek Vasut regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31),
1952905086dSMarek Vasut regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW),
1962905086dSMarek Vasut regmap_reg_range(DA9063_REG_CONFIG_I, DA9063_BB_REG_MON_REG_4),
1972905086dSMarek Vasut regmap_reg_range(DA9063_BB_REG_GP_ID_0, DA9063_BB_REG_GP_ID_19),
1989cb42e2aSOpensource [Steve Twiss] };
1999cb42e2aSOpensource [Steve Twiss]
2009ece3601SAdam Thomson static const struct regmap_range da9063_bb_da_volatile_ranges[] = {
2012905086dSMarek Vasut regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_EVENT_D),
2022905086dSMarek Vasut regmap_reg_range(DA9063_REG_CONTROL_A, DA9063_REG_CONTROL_B),
2032905086dSMarek Vasut regmap_reg_range(DA9063_REG_CONTROL_E, DA9063_REG_CONTROL_F),
2042905086dSMarek Vasut regmap_reg_range(DA9063_REG_BCORE2_CONT, DA9063_REG_LDO11_CONT),
2052905086dSMarek Vasut regmap_reg_range(DA9063_REG_DVC_1, DA9063_REG_ADC_MAN),
2062905086dSMarek Vasut regmap_reg_range(DA9063_REG_ADC_RES_L, DA9063_BB_REG_SECOND_D),
2072905086dSMarek Vasut regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_SEQ),
2082905086dSMarek Vasut regmap_reg_range(DA9063_REG_EN_32K, DA9063_REG_EN_32K),
2092905086dSMarek Vasut regmap_reg_range(DA9063_BB_REG_MON_REG_5, DA9063_BB_REG_MON_REG_6),
2109cb42e2aSOpensource [Steve Twiss] };
2119cb42e2aSOpensource [Steve Twiss]
2129cb42e2aSOpensource [Steve Twiss] static const struct regmap_access_table da9063_bb_readable_table = {
2139cb42e2aSOpensource [Steve Twiss] .yes_ranges = da9063_bb_readable_ranges,
2149cb42e2aSOpensource [Steve Twiss] .n_yes_ranges = ARRAY_SIZE(da9063_bb_readable_ranges),
2159cb42e2aSOpensource [Steve Twiss] };
2169cb42e2aSOpensource [Steve Twiss]
2179cb42e2aSOpensource [Steve Twiss] static const struct regmap_access_table da9063_bb_writeable_table = {
2189cb42e2aSOpensource [Steve Twiss] .yes_ranges = da9063_bb_writeable_ranges,
2199cb42e2aSOpensource [Steve Twiss] .n_yes_ranges = ARRAY_SIZE(da9063_bb_writeable_ranges),
2209cb42e2aSOpensource [Steve Twiss] };
2219cb42e2aSOpensource [Steve Twiss]
2229ece3601SAdam Thomson static const struct regmap_access_table da9063_bb_da_volatile_table = {
2239ece3601SAdam Thomson .yes_ranges = da9063_bb_da_volatile_ranges,
2249ece3601SAdam Thomson .n_yes_ranges = ARRAY_SIZE(da9063_bb_da_volatile_ranges),
2258e685483SKrystian Garbaciak };
2268e685483SKrystian Garbaciak
2274bd6ad0aSMarek Vasut static const struct regmap_range da9063l_bb_readable_ranges[] = {
2284bd6ad0aSMarek Vasut regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_MON_A10_RES),
2294bd6ad0aSMarek Vasut regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31),
2304bd6ad0aSMarek Vasut regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW),
2314bd6ad0aSMarek Vasut regmap_reg_range(DA9063_REG_T_OFFSET, DA9063_BB_REG_GP_ID_19),
232091c6110SAdam Thomson regmap_reg_range(DA9063_REG_DEVICE_ID, DA9063_REG_VARIANT_ID),
2334bd6ad0aSMarek Vasut };
2344bd6ad0aSMarek Vasut
2354bd6ad0aSMarek Vasut static const struct regmap_range da9063l_bb_writeable_ranges[] = {
2364bd6ad0aSMarek Vasut regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_PAGE_CON),
2374bd6ad0aSMarek Vasut regmap_reg_range(DA9063_REG_FAULT_LOG, DA9063_REG_VSYS_MON),
2384bd6ad0aSMarek Vasut regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31),
2394bd6ad0aSMarek Vasut regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW),
2404bd6ad0aSMarek Vasut regmap_reg_range(DA9063_REG_CONFIG_I, DA9063_BB_REG_MON_REG_4),
2414bd6ad0aSMarek Vasut regmap_reg_range(DA9063_BB_REG_GP_ID_0, DA9063_BB_REG_GP_ID_19),
2424bd6ad0aSMarek Vasut };
2434bd6ad0aSMarek Vasut
2449ece3601SAdam Thomson static const struct regmap_range da9063l_bb_da_volatile_ranges[] = {
2454bd6ad0aSMarek Vasut regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_EVENT_D),
2464bd6ad0aSMarek Vasut regmap_reg_range(DA9063_REG_CONTROL_A, DA9063_REG_CONTROL_B),
2474bd6ad0aSMarek Vasut regmap_reg_range(DA9063_REG_CONTROL_E, DA9063_REG_CONTROL_F),
2484bd6ad0aSMarek Vasut regmap_reg_range(DA9063_REG_BCORE2_CONT, DA9063_REG_LDO11_CONT),
2494bd6ad0aSMarek Vasut regmap_reg_range(DA9063_REG_DVC_1, DA9063_REG_ADC_MAN),
2504bd6ad0aSMarek Vasut regmap_reg_range(DA9063_REG_ADC_RES_L, DA9063_REG_MON_A10_RES),
2514bd6ad0aSMarek Vasut regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_SEQ),
2524bd6ad0aSMarek Vasut regmap_reg_range(DA9063_REG_EN_32K, DA9063_REG_EN_32K),
2534bd6ad0aSMarek Vasut regmap_reg_range(DA9063_BB_REG_MON_REG_5, DA9063_BB_REG_MON_REG_6),
2544bd6ad0aSMarek Vasut };
2554bd6ad0aSMarek Vasut
2564bd6ad0aSMarek Vasut static const struct regmap_access_table da9063l_bb_readable_table = {
2574bd6ad0aSMarek Vasut .yes_ranges = da9063l_bb_readable_ranges,
2584bd6ad0aSMarek Vasut .n_yes_ranges = ARRAY_SIZE(da9063l_bb_readable_ranges),
2594bd6ad0aSMarek Vasut };
2604bd6ad0aSMarek Vasut
2614bd6ad0aSMarek Vasut static const struct regmap_access_table da9063l_bb_writeable_table = {
2624bd6ad0aSMarek Vasut .yes_ranges = da9063l_bb_writeable_ranges,
2634bd6ad0aSMarek Vasut .n_yes_ranges = ARRAY_SIZE(da9063l_bb_writeable_ranges),
2644bd6ad0aSMarek Vasut };
2654bd6ad0aSMarek Vasut
2669ece3601SAdam Thomson static const struct regmap_access_table da9063l_bb_da_volatile_table = {
2679ece3601SAdam Thomson .yes_ranges = da9063l_bb_da_volatile_ranges,
2689ece3601SAdam Thomson .n_yes_ranges = ARRAY_SIZE(da9063l_bb_da_volatile_ranges),
2699ece3601SAdam Thomson };
2709ece3601SAdam Thomson
2719ece3601SAdam Thomson static const struct regmap_range da9063_da_readable_ranges[] = {
2729ece3601SAdam Thomson regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_BB_REG_SECOND_D),
2739ece3601SAdam Thomson regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31),
2749ece3601SAdam Thomson regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW),
2759ece3601SAdam Thomson regmap_reg_range(DA9063_REG_T_OFFSET, DA9063_BB_REG_GP_ID_11),
2769ece3601SAdam Thomson regmap_reg_range(DA9063_REG_DEVICE_ID, DA9063_REG_VARIANT_ID),
2779ece3601SAdam Thomson };
2789ece3601SAdam Thomson
2799ece3601SAdam Thomson static const struct regmap_range da9063_da_writeable_ranges[] = {
2809ece3601SAdam Thomson regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_PAGE_CON),
2819ece3601SAdam Thomson regmap_reg_range(DA9063_REG_FAULT_LOG, DA9063_REG_VSYS_MON),
2829ece3601SAdam Thomson regmap_reg_range(DA9063_REG_COUNT_S, DA9063_BB_REG_ALARM_Y),
2839ece3601SAdam Thomson regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31),
2849ece3601SAdam Thomson regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW),
2859ece3601SAdam Thomson regmap_reg_range(DA9063_REG_CONFIG_I, DA9063_BB_REG_MON_REG_4),
2869ece3601SAdam Thomson regmap_reg_range(DA9063_BB_REG_GP_ID_0, DA9063_BB_REG_GP_ID_11),
2879ece3601SAdam Thomson };
2889ece3601SAdam Thomson
2899ece3601SAdam Thomson static const struct regmap_access_table da9063_da_readable_table = {
2909ece3601SAdam Thomson .yes_ranges = da9063_da_readable_ranges,
2919ece3601SAdam Thomson .n_yes_ranges = ARRAY_SIZE(da9063_da_readable_ranges),
2929ece3601SAdam Thomson };
2939ece3601SAdam Thomson
2949ece3601SAdam Thomson static const struct regmap_access_table da9063_da_writeable_table = {
2959ece3601SAdam Thomson .yes_ranges = da9063_da_writeable_ranges,
2969ece3601SAdam Thomson .n_yes_ranges = ARRAY_SIZE(da9063_da_writeable_ranges),
2979ece3601SAdam Thomson };
2989ece3601SAdam Thomson
2999ece3601SAdam Thomson static const struct regmap_range da9063l_da_readable_ranges[] = {
3009ece3601SAdam Thomson regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_MON_A10_RES),
3019ece3601SAdam Thomson regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31),
3029ece3601SAdam Thomson regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW),
3039ece3601SAdam Thomson regmap_reg_range(DA9063_REG_T_OFFSET, DA9063_BB_REG_GP_ID_11),
3049ece3601SAdam Thomson regmap_reg_range(DA9063_REG_DEVICE_ID, DA9063_REG_VARIANT_ID),
3059ece3601SAdam Thomson };
3069ece3601SAdam Thomson
3079ece3601SAdam Thomson static const struct regmap_range da9063l_da_writeable_ranges[] = {
3089ece3601SAdam Thomson regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_PAGE_CON),
3099ece3601SAdam Thomson regmap_reg_range(DA9063_REG_FAULT_LOG, DA9063_REG_VSYS_MON),
3109ece3601SAdam Thomson regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31),
3119ece3601SAdam Thomson regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW),
3129ece3601SAdam Thomson regmap_reg_range(DA9063_REG_CONFIG_I, DA9063_BB_REG_MON_REG_4),
3139ece3601SAdam Thomson regmap_reg_range(DA9063_BB_REG_GP_ID_0, DA9063_BB_REG_GP_ID_11),
3149ece3601SAdam Thomson };
3159ece3601SAdam Thomson
3169ece3601SAdam Thomson static const struct regmap_access_table da9063l_da_readable_table = {
3179ece3601SAdam Thomson .yes_ranges = da9063l_da_readable_ranges,
3189ece3601SAdam Thomson .n_yes_ranges = ARRAY_SIZE(da9063l_da_readable_ranges),
3199ece3601SAdam Thomson };
3209ece3601SAdam Thomson
3219ece3601SAdam Thomson static const struct regmap_access_table da9063l_da_writeable_table = {
3229ece3601SAdam Thomson .yes_ranges = da9063l_da_writeable_ranges,
3239ece3601SAdam Thomson .n_yes_ranges = ARRAY_SIZE(da9063l_da_writeable_ranges),
3244bd6ad0aSMarek Vasut };
3254bd6ad0aSMarek Vasut
3268e685483SKrystian Garbaciak static const struct regmap_range_cfg da9063_range_cfg[] = {
3278e685483SKrystian Garbaciak {
3288e685483SKrystian Garbaciak .range_min = DA9063_REG_PAGE_CON,
329091c6110SAdam Thomson .range_max = DA9063_REG_CONFIG_ID,
3308e685483SKrystian Garbaciak .selector_reg = DA9063_REG_PAGE_CON,
3318e685483SKrystian Garbaciak .selector_mask = 1 << DA9063_I2C_PAGE_SEL_SHIFT,
3328e685483SKrystian Garbaciak .selector_shift = DA9063_I2C_PAGE_SEL_SHIFT,
3338e685483SKrystian Garbaciak .window_start = 0,
3348e685483SKrystian Garbaciak .window_len = 256,
3358e685483SKrystian Garbaciak }
3368e685483SKrystian Garbaciak };
3378e685483SKrystian Garbaciak
3388e685483SKrystian Garbaciak static struct regmap_config da9063_regmap_config = {
3398e685483SKrystian Garbaciak .reg_bits = 8,
3408e685483SKrystian Garbaciak .val_bits = 8,
3418e685483SKrystian Garbaciak .ranges = da9063_range_cfg,
3428e685483SKrystian Garbaciak .num_ranges = ARRAY_SIZE(da9063_range_cfg),
343091c6110SAdam Thomson .max_register = DA9063_REG_CONFIG_ID,
3448e685483SKrystian Garbaciak
3458e685483SKrystian Garbaciak .cache_type = REGCACHE_RBTREE,
3468e685483SKrystian Garbaciak };
3478e685483SKrystian Garbaciak
34871e03de4SSteve Twiss static const struct of_device_id da9063_dt_ids[] = {
34971e03de4SSteve Twiss { .compatible = "dlg,da9063", },
350c287572bSMarek Vasut { .compatible = "dlg,da9063l", },
35171e03de4SSteve Twiss { }
35271e03de4SSteve Twiss };
35371e03de4SSteve Twiss MODULE_DEVICE_TABLE(of, da9063_dt_ids);
da9063_i2c_probe(struct i2c_client * i2c)354b309636bSUwe Kleine-König static int da9063_i2c_probe(struct i2c_client *i2c)
3558e685483SKrystian Garbaciak {
356b309636bSUwe Kleine-König const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
3578e685483SKrystian Garbaciak struct da9063 *da9063;
3588e685483SKrystian Garbaciak int ret;
3598e685483SKrystian Garbaciak
3608e685483SKrystian Garbaciak da9063 = devm_kzalloc(&i2c->dev, sizeof(struct da9063), GFP_KERNEL);
3618e685483SKrystian Garbaciak if (da9063 == NULL)
3628e685483SKrystian Garbaciak return -ENOMEM;
3638e685483SKrystian Garbaciak
3648e685483SKrystian Garbaciak i2c_set_clientdata(i2c, da9063);
3658e685483SKrystian Garbaciak da9063->dev = &i2c->dev;
3668e685483SKrystian Garbaciak da9063->chip_irq = i2c->irq;
367492510ddSMarek Vasut da9063->type = id->driver_data;
3688e685483SKrystian Garbaciak
369091c6110SAdam Thomson ret = da9063_get_device_type(i2c, da9063);
370091c6110SAdam Thomson if (ret)
371091c6110SAdam Thomson return ret;
372091c6110SAdam Thomson
373091c6110SAdam Thomson switch (da9063->type) {
374091c6110SAdam Thomson case PMIC_TYPE_DA9063:
375091c6110SAdam Thomson switch (da9063->variant_code) {
376091c6110SAdam Thomson case PMIC_DA9063_AD:
377091c6110SAdam Thomson da9063_regmap_config.rd_table =
378091c6110SAdam Thomson &da9063_ad_readable_table;
379091c6110SAdam Thomson da9063_regmap_config.wr_table =
380091c6110SAdam Thomson &da9063_ad_writeable_table;
381091c6110SAdam Thomson da9063_regmap_config.volatile_table =
382091c6110SAdam Thomson &da9063_ad_volatile_table;
383091c6110SAdam Thomson break;
384091c6110SAdam Thomson case PMIC_DA9063_BB:
385091c6110SAdam Thomson case PMIC_DA9063_CA:
386091c6110SAdam Thomson da9063_regmap_config.rd_table =
387091c6110SAdam Thomson &da9063_bb_readable_table;
388091c6110SAdam Thomson da9063_regmap_config.wr_table =
389091c6110SAdam Thomson &da9063_bb_writeable_table;
390091c6110SAdam Thomson da9063_regmap_config.volatile_table =
3919ece3601SAdam Thomson &da9063_bb_da_volatile_table;
3929ece3601SAdam Thomson break;
3939ece3601SAdam Thomson case PMIC_DA9063_DA:
394c9a20383SCarlos de Paula case PMIC_DA9063_EA:
3959ece3601SAdam Thomson da9063_regmap_config.rd_table =
3969ece3601SAdam Thomson &da9063_da_readable_table;
3979ece3601SAdam Thomson da9063_regmap_config.wr_table =
3989ece3601SAdam Thomson &da9063_da_writeable_table;
3999ece3601SAdam Thomson da9063_regmap_config.volatile_table =
4009ece3601SAdam Thomson &da9063_bb_da_volatile_table;
401091c6110SAdam Thomson break;
402091c6110SAdam Thomson default:
403091c6110SAdam Thomson dev_err(da9063->dev,
404091c6110SAdam Thomson "Chip variant not supported for DA9063\n");
405091c6110SAdam Thomson return -ENODEV;
406091c6110SAdam Thomson }
407091c6110SAdam Thomson break;
408091c6110SAdam Thomson case PMIC_TYPE_DA9063L:
409091c6110SAdam Thomson switch (da9063->variant_code) {
410091c6110SAdam Thomson case PMIC_DA9063_BB:
411091c6110SAdam Thomson case PMIC_DA9063_CA:
412091c6110SAdam Thomson da9063_regmap_config.rd_table =
413091c6110SAdam Thomson &da9063l_bb_readable_table;
414091c6110SAdam Thomson da9063_regmap_config.wr_table =
415091c6110SAdam Thomson &da9063l_bb_writeable_table;
416091c6110SAdam Thomson da9063_regmap_config.volatile_table =
4179ece3601SAdam Thomson &da9063l_bb_da_volatile_table;
4189ece3601SAdam Thomson break;
4199ece3601SAdam Thomson case PMIC_DA9063_DA:
420c9a20383SCarlos de Paula case PMIC_DA9063_EA:
4219ece3601SAdam Thomson da9063_regmap_config.rd_table =
4229ece3601SAdam Thomson &da9063l_da_readable_table;
4239ece3601SAdam Thomson da9063_regmap_config.wr_table =
4249ece3601SAdam Thomson &da9063l_da_writeable_table;
4259ece3601SAdam Thomson da9063_regmap_config.volatile_table =
4269ece3601SAdam Thomson &da9063l_bb_da_volatile_table;
427091c6110SAdam Thomson break;
428091c6110SAdam Thomson default:
429091c6110SAdam Thomson dev_err(da9063->dev,
430091c6110SAdam Thomson "Chip variant not supported for DA9063L\n");
431091c6110SAdam Thomson return -ENODEV;
432091c6110SAdam Thomson }
433091c6110SAdam Thomson break;
434091c6110SAdam Thomson default:
435091c6110SAdam Thomson dev_err(da9063->dev, "Chip type not supported\n");
436091c6110SAdam Thomson return -ENODEV;
4379cb42e2aSOpensource [Steve Twiss] }
4389cb42e2aSOpensource [Steve Twiss]
4398e685483SKrystian Garbaciak da9063->regmap = devm_regmap_init_i2c(i2c, &da9063_regmap_config);
4408e685483SKrystian Garbaciak if (IS_ERR(da9063->regmap)) {
4418e685483SKrystian Garbaciak ret = PTR_ERR(da9063->regmap);
4428e685483SKrystian Garbaciak dev_err(da9063->dev, "Failed to allocate register map: %d\n",
4438e685483SKrystian Garbaciak ret);
4448e685483SKrystian Garbaciak return ret;
4458e685483SKrystian Garbaciak }
4468e685483SKrystian Garbaciak
447586478bfSHubert Streidl /* If SMBus is not available and only I2C is possible, enter I2C mode */
448586478bfSHubert Streidl if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) {
449586478bfSHubert Streidl ret = regmap_clear_bits(da9063->regmap, DA9063_REG_CONFIG_J,
450586478bfSHubert Streidl DA9063_TWOWIRE_TO);
451586478bfSHubert Streidl if (ret < 0) {
452586478bfSHubert Streidl dev_err(da9063->dev, "Failed to set Two-Wire Bus Mode.\n");
453921071a8SWolfram Sang return ret;
454586478bfSHubert Streidl }
455586478bfSHubert Streidl }
456586478bfSHubert Streidl
4578e685483SKrystian Garbaciak return da9063_device_init(da9063, i2c->irq);
4588e685483SKrystian Garbaciak }
4598e685483SKrystian Garbaciak
4608e685483SKrystian Garbaciak static const struct i2c_device_id da9063_i2c_id[] = {
461492510ddSMarek Vasut { "da9063", PMIC_TYPE_DA9063 },
462c287572bSMarek Vasut { "da9063l", PMIC_TYPE_DA9063L },
4638e685483SKrystian Garbaciak {},
4648e685483SKrystian Garbaciak };
4658e685483SKrystian Garbaciak MODULE_DEVICE_TABLE(i2c, da9063_i2c_id);
4668e685483SKrystian Garbaciak
4678e685483SKrystian Garbaciak static struct i2c_driver da9063_i2c_driver = {
4688e685483SKrystian Garbaciak .driver = {
4698e685483SKrystian Garbaciak .name = "da9063",
4705f2bf438SKrzysztof Kozlowski .of_match_table = da9063_dt_ids,
4718e685483SKrystian Garbaciak },
472*9816d859SUwe Kleine-König .probe = da9063_i2c_probe,
4738e685483SKrystian Garbaciak .id_table = da9063_i2c_id,
4748e685483SKrystian Garbaciak };
4758e685483SKrystian Garbaciak
4768e685483SKrystian Garbaciak module_i2c_driver(da9063_i2c_driver);
477