summaryrefslogtreecommitdiffstats
path: root/drivers/mfd/rk8xx-i2c.c
blob: 37287b06dab0d4f7ac3a1add8ac16f87e598e390 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Rockchip RK805/RK808/RK816/RK817/RK818 Core (I2C) driver
 *
 * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
 * Copyright (C) 2016 PHYTEC Messtechnik GmbH
 *
 * Author: Chris Zhong <zyw@rock-chips.com>
 * Author: Zhang Qing <zhangqing@rock-chips.com>
 * Author: Wadim Egorov <w.egorov@phytec.de>
 */

#include <linux/i2c.h>
#include <linux/mfd/rk808.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regmap.h>

struct rk8xx_i2c_platform_data {
	const struct regmap_config *regmap_cfg;
	int variant;
};

static bool rk806_is_volatile_reg(struct device *dev, unsigned int reg)
{
	switch (reg) {
	case RK806_POWER_EN0 ... RK806_POWER_EN5:
	case RK806_DVS_START_CTRL ... RK806_INT_MSK1:
		return true;
	}

	return false;
}

static bool rk808_is_volatile_reg(struct device *dev, unsigned int reg)
{
	/*
	 * Notes:
	 * - Technically the ROUND_30s bit makes RTC_CTRL_REG volatile, but
	 *   we don't use that feature.  It's better to cache.
	 * - It's unlikely we care that RK808_DEVCTRL_REG is volatile since
	 *   bits are cleared in case when we shutoff anyway, but better safe.
	 */

	switch (reg) {
	case RK808_SECONDS_REG ... RK808_WEEKS_REG:
	case RK808_RTC_STATUS_REG:
	case RK808_VB_MON_REG:
	case RK808_THERMAL_REG:
	case RK808_DCDC_UV_STS_REG:
	case RK808_LDO_UV_STS_REG:
	case RK808_DCDC_PG_REG:
	case RK808_LDO_PG_REG:
	case RK808_DEVCTRL_REG:
	case RK808_INT_STS_REG1:
	case RK808_INT_STS_REG2:
		return true;
	}

	return false;
}

static bool rk816_is_volatile_reg(struct device *dev, unsigned int reg)
{
	/*
	 * Technically the ROUND_30s bit makes RTC_CTRL_REG volatile, but
	 * we don't use that feature.  It's better to cache.
	 */

	switch (reg) {
	case RK808_SECONDS_REG ... RK808_WEEKS_REG:
	case RK808_RTC_STATUS_REG:
	case RK808_VB_MON_REG:
	case RK808_THERMAL_REG:
	case RK816_DCDC_EN_REG1:
	case RK816_DCDC_EN_REG2:
	case RK816_INT_STS_REG1:
	case RK816_INT_STS_REG2:
	case RK816_INT_STS_REG3:
	case RK808_DEVCTRL_REG:
	case RK816_SUP_STS_REG:
	case RK816_GGSTS_REG:
	case RK816_ZERO_CUR_ADC_REGH:
	case RK816_ZERO_CUR_ADC_REGL:
	case RK816_GASCNT_REG(0) ... RK816_BAT_VOL_REGL:
		return true;
	}

	return false;
}

static bool rk817_is_volatile_reg(struct device *dev, unsigned int reg)
{
	/*
	 * Notes:
	 * - Technically the ROUND_30s bit makes RTC_CTRL_REG volatile, but
	 *   we don't use that feature.  It's better to cache.
	 */

	switch (reg) {
	case RK817_SECONDS_REG ... RK817_WEEKS_REG:
	case RK817_RTC_STATUS_REG:
	case RK817_CODEC_DTOP_LPT_SRST:
	case RK817_GAS_GAUGE_ADC_CONFIG0 ... RK817_GAS_GAUGE_CUR_ADC_K0:
	case RK817_PMIC_CHRG_STS:
	case RK817_PMIC_CHRG_OUT:
	case RK817_PMIC_CHRG_IN:
	case RK817_INT_STS_REG0:
	case RK817_INT_STS_REG1:
	case RK817_INT_STS_REG2:
	case RK817_SYS_STS:
		return true;
	}

	return false;
}


static const struct regmap_config rk818_regmap_config = {
	.reg_bits = 8,
	.val_bits = 8,
	.max_register = RK818_USB_CTRL_REG,
	.cache_type = REGCACHE_MAPLE,
	.volatile_reg = rk808_is_volatile_reg,
};

static const struct regmap_config rk805_regmap_config = {
	.reg_bits = 8,
	.val_bits = 8,
	.max_register = RK805_OFF_SOURCE_REG,
	.cache_type = REGCACHE_MAPLE,
	.volatile_reg = rk808_is_volatile_reg,
};

static const struct regmap_config rk806_regmap_config = {
	.reg_bits = 8,
	.val_bits = 8,
	.max_register = RK806_BUCK_RSERVE_REG5,
	.cache_type = REGCACHE_MAPLE,
	.volatile_reg = rk806_is_volatile_reg,
};

static const struct regmap_config rk808_regmap_config = {
	.reg_bits = 8,
	.val_bits = 8,
	.max_register = RK808_IO_POL_REG,
	.cache_type = REGCACHE_MAPLE,
	.volatile_reg = rk808_is_volatile_reg,
};

static const struct regmap_config rk816_regmap_config = {
	.reg_bits = 8,
	.val_bits = 8,
	.max_register = RK816_DATA_REG(18),
	.cache_type = REGCACHE_MAPLE,
	.volatile_reg = rk816_is_volatile_reg,
};

static const struct regmap_config rk817_regmap_config = {
	.reg_bits = 8,
	.val_bits = 8,
	.max_register = RK817_GPIO_INT_CFG,
	.cache_type = REGCACHE_NONE,
	.volatile_reg = rk817_is_volatile_reg,
};

static const struct rk8xx_i2c_platform_data rk805_data = {
	.regmap_cfg = &rk805_regmap_config,
	.variant = RK805_ID,
};

static const struct rk8xx_i2c_platform_data rk806_data = {
	.regmap_cfg = &rk806_regmap_config,
	.variant = RK806_ID,
};

static const struct rk8xx_i2c_platform_data rk808_data = {
	.regmap_cfg = &rk808_regmap_config,
	.variant = RK808_ID,
};

static const struct rk8xx_i2c_platform_data rk809_data = {
	.regmap_cfg = &rk817_regmap_config,
	.variant = RK809_ID,
};

static const struct rk8xx_i2c_platform_data rk816_data = {
	.regmap_cfg = &rk816_regmap_config,
	.variant = RK816_ID,
};

static const struct rk8xx_i2c_platform_data rk817_data = {
	.regmap_cfg = &rk817_regmap_config,
	.variant = RK817_ID,
};

static const struct rk8xx_i2c_platform_data rk818_data = {
	.regmap_cfg = &rk818_regmap_config,
	.variant = RK818_ID,
};

static int rk8xx_i2c_probe(struct i2c_client *client)
{
	const struct rk8xx_i2c_platform_data *data;
	struct regmap *regmap;

	data = device_get_match_data(&client->dev);
	if (!data)
		return -ENODEV;

	regmap = devm_regmap_init_i2c(client, data->regmap_cfg);
	if (IS_ERR(regmap))
		return dev_err_probe(&client->dev, PTR_ERR(regmap),
				     "regmap initialization failed\n");

	return rk8xx_probe(&client->dev, data->variant, client->irq, regmap);
}

static void rk8xx_i2c_shutdown(struct i2c_client *client)
{
	rk8xx_shutdown(&client->dev);
}

static SIMPLE_DEV_PM_OPS(rk8xx_i2c_pm_ops, rk8xx_suspend, rk8xx_resume);

static const struct of_device_id rk8xx_i2c_of_match[] = {
	{ .compatible = "rockchip,rk805", .data = &rk805_data },
	{ .compatible = "rockchip,rk806", .data = &rk806_data },
	{ .compatible = "rockchip,rk808", .data = &rk808_data },
	{ .compatible = "rockchip,rk809", .data = &rk809_data },
	{ .compatible = "rockchip,rk816", .data = &rk816_data },
	{ .compatible = "rockchip,rk817", .data = &rk817_data },
	{ .compatible = "rockchip,rk818", .data = &rk818_data },
	{ },
};
MODULE_DEVICE_TABLE(of, rk8xx_i2c_of_match);

static struct i2c_driver rk8xx_i2c_driver = {
	.driver = {
		.name = "rk8xx-i2c",
		.of_match_table = rk8xx_i2c_of_match,
		.pm = &rk8xx_i2c_pm_ops,
	},
	.probe = rk8xx_i2c_probe,
	.shutdown  = rk8xx_i2c_shutdown,
};
module_i2c_driver(rk8xx_i2c_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
MODULE_AUTHOR("Zhang Qing <zhangqing@rock-chips.com>");
MODULE_AUTHOR("Wadim Egorov <w.egorov@phytec.de>");
MODULE_DESCRIPTION("RK8xx I2C PMIC driver");