summaryrefslogtreecommitdiffstats
path: root/drivers/mfd/rk8xx-i2c.c
blob: 1a98feea97e2c5bc8301623323852ca6ef5b71de (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
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Rockchip RK808/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 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 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_RBTREE,
	.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_RBTREE,
	.volatile_reg = rk808_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_RBTREE,
	.volatile_reg = rk808_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 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 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,rk808", .data = &rk808_data },
	{ .compatible = "rockchip,rk809", .data = &rk809_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");