162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Rockchip RK808/RK818 Core (I2C) driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
662306a36Sopenharmony_ci * Copyright (C) 2016 PHYTEC Messtechnik GmbH
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Author: Chris Zhong <zyw@rock-chips.com>
962306a36Sopenharmony_ci * Author: Zhang Qing <zhangqing@rock-chips.com>
1062306a36Sopenharmony_ci * Author: Wadim Egorov <w.egorov@phytec.de>
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/i2c.h>
1462306a36Sopenharmony_ci#include <linux/mfd/rk808.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/of.h>
1762306a36Sopenharmony_ci#include <linux/regmap.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistruct rk8xx_i2c_platform_data {
2062306a36Sopenharmony_ci	const struct regmap_config *regmap_cfg;
2162306a36Sopenharmony_ci	int variant;
2262306a36Sopenharmony_ci};
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic bool rk808_is_volatile_reg(struct device *dev, unsigned int reg)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	/*
2762306a36Sopenharmony_ci	 * Notes:
2862306a36Sopenharmony_ci	 * - Technically the ROUND_30s bit makes RTC_CTRL_REG volatile, but
2962306a36Sopenharmony_ci	 *   we don't use that feature.  It's better to cache.
3062306a36Sopenharmony_ci	 * - It's unlikely we care that RK808_DEVCTRL_REG is volatile since
3162306a36Sopenharmony_ci	 *   bits are cleared in case when we shutoff anyway, but better safe.
3262306a36Sopenharmony_ci	 */
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	switch (reg) {
3562306a36Sopenharmony_ci	case RK808_SECONDS_REG ... RK808_WEEKS_REG:
3662306a36Sopenharmony_ci	case RK808_RTC_STATUS_REG:
3762306a36Sopenharmony_ci	case RK808_VB_MON_REG:
3862306a36Sopenharmony_ci	case RK808_THERMAL_REG:
3962306a36Sopenharmony_ci	case RK808_DCDC_UV_STS_REG:
4062306a36Sopenharmony_ci	case RK808_LDO_UV_STS_REG:
4162306a36Sopenharmony_ci	case RK808_DCDC_PG_REG:
4262306a36Sopenharmony_ci	case RK808_LDO_PG_REG:
4362306a36Sopenharmony_ci	case RK808_DEVCTRL_REG:
4462306a36Sopenharmony_ci	case RK808_INT_STS_REG1:
4562306a36Sopenharmony_ci	case RK808_INT_STS_REG2:
4662306a36Sopenharmony_ci		return true;
4762306a36Sopenharmony_ci	}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	return false;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic bool rk817_is_volatile_reg(struct device *dev, unsigned int reg)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	/*
5562306a36Sopenharmony_ci	 * Notes:
5662306a36Sopenharmony_ci	 * - Technically the ROUND_30s bit makes RTC_CTRL_REG volatile, but
5762306a36Sopenharmony_ci	 *   we don't use that feature.  It's better to cache.
5862306a36Sopenharmony_ci	 */
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	switch (reg) {
6162306a36Sopenharmony_ci	case RK817_SECONDS_REG ... RK817_WEEKS_REG:
6262306a36Sopenharmony_ci	case RK817_RTC_STATUS_REG:
6362306a36Sopenharmony_ci	case RK817_CODEC_DTOP_LPT_SRST:
6462306a36Sopenharmony_ci	case RK817_GAS_GAUGE_ADC_CONFIG0 ... RK817_GAS_GAUGE_CUR_ADC_K0:
6562306a36Sopenharmony_ci	case RK817_PMIC_CHRG_STS:
6662306a36Sopenharmony_ci	case RK817_PMIC_CHRG_OUT:
6762306a36Sopenharmony_ci	case RK817_PMIC_CHRG_IN:
6862306a36Sopenharmony_ci	case RK817_INT_STS_REG0:
6962306a36Sopenharmony_ci	case RK817_INT_STS_REG1:
7062306a36Sopenharmony_ci	case RK817_INT_STS_REG2:
7162306a36Sopenharmony_ci	case RK817_SYS_STS:
7262306a36Sopenharmony_ci		return true;
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	return false;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic const struct regmap_config rk818_regmap_config = {
8062306a36Sopenharmony_ci	.reg_bits = 8,
8162306a36Sopenharmony_ci	.val_bits = 8,
8262306a36Sopenharmony_ci	.max_register = RK818_USB_CTRL_REG,
8362306a36Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
8462306a36Sopenharmony_ci	.volatile_reg = rk808_is_volatile_reg,
8562306a36Sopenharmony_ci};
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic const struct regmap_config rk805_regmap_config = {
8862306a36Sopenharmony_ci	.reg_bits = 8,
8962306a36Sopenharmony_ci	.val_bits = 8,
9062306a36Sopenharmony_ci	.max_register = RK805_OFF_SOURCE_REG,
9162306a36Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
9262306a36Sopenharmony_ci	.volatile_reg = rk808_is_volatile_reg,
9362306a36Sopenharmony_ci};
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic const struct regmap_config rk808_regmap_config = {
9662306a36Sopenharmony_ci	.reg_bits = 8,
9762306a36Sopenharmony_ci	.val_bits = 8,
9862306a36Sopenharmony_ci	.max_register = RK808_IO_POL_REG,
9962306a36Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
10062306a36Sopenharmony_ci	.volatile_reg = rk808_is_volatile_reg,
10162306a36Sopenharmony_ci};
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic const struct regmap_config rk817_regmap_config = {
10462306a36Sopenharmony_ci	.reg_bits = 8,
10562306a36Sopenharmony_ci	.val_bits = 8,
10662306a36Sopenharmony_ci	.max_register = RK817_GPIO_INT_CFG,
10762306a36Sopenharmony_ci	.cache_type = REGCACHE_NONE,
10862306a36Sopenharmony_ci	.volatile_reg = rk817_is_volatile_reg,
10962306a36Sopenharmony_ci};
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic const struct rk8xx_i2c_platform_data rk805_data = {
11262306a36Sopenharmony_ci	.regmap_cfg = &rk805_regmap_config,
11362306a36Sopenharmony_ci	.variant = RK805_ID,
11462306a36Sopenharmony_ci};
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic const struct rk8xx_i2c_platform_data rk808_data = {
11762306a36Sopenharmony_ci	.regmap_cfg = &rk808_regmap_config,
11862306a36Sopenharmony_ci	.variant = RK808_ID,
11962306a36Sopenharmony_ci};
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic const struct rk8xx_i2c_platform_data rk809_data = {
12262306a36Sopenharmony_ci	.regmap_cfg = &rk817_regmap_config,
12362306a36Sopenharmony_ci	.variant = RK809_ID,
12462306a36Sopenharmony_ci};
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic const struct rk8xx_i2c_platform_data rk817_data = {
12762306a36Sopenharmony_ci	.regmap_cfg = &rk817_regmap_config,
12862306a36Sopenharmony_ci	.variant = RK817_ID,
12962306a36Sopenharmony_ci};
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic const struct rk8xx_i2c_platform_data rk818_data = {
13262306a36Sopenharmony_ci	.regmap_cfg = &rk818_regmap_config,
13362306a36Sopenharmony_ci	.variant = RK818_ID,
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic int rk8xx_i2c_probe(struct i2c_client *client)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	const struct rk8xx_i2c_platform_data *data;
13962306a36Sopenharmony_ci	struct regmap *regmap;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	data = device_get_match_data(&client->dev);
14262306a36Sopenharmony_ci	if (!data)
14362306a36Sopenharmony_ci		return -ENODEV;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	regmap = devm_regmap_init_i2c(client, data->regmap_cfg);
14662306a36Sopenharmony_ci	if (IS_ERR(regmap))
14762306a36Sopenharmony_ci		return dev_err_probe(&client->dev, PTR_ERR(regmap),
14862306a36Sopenharmony_ci				     "regmap initialization failed\n");
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	return rk8xx_probe(&client->dev, data->variant, client->irq, regmap);
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic void rk8xx_i2c_shutdown(struct i2c_client *client)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	rk8xx_shutdown(&client->dev);
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(rk8xx_i2c_pm_ops, rk8xx_suspend, rk8xx_resume);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic const struct of_device_id rk8xx_i2c_of_match[] = {
16162306a36Sopenharmony_ci	{ .compatible = "rockchip,rk805", .data = &rk805_data },
16262306a36Sopenharmony_ci	{ .compatible = "rockchip,rk808", .data = &rk808_data },
16362306a36Sopenharmony_ci	{ .compatible = "rockchip,rk809", .data = &rk809_data },
16462306a36Sopenharmony_ci	{ .compatible = "rockchip,rk817", .data = &rk817_data },
16562306a36Sopenharmony_ci	{ .compatible = "rockchip,rk818", .data = &rk818_data },
16662306a36Sopenharmony_ci	{ },
16762306a36Sopenharmony_ci};
16862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rk8xx_i2c_of_match);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic struct i2c_driver rk8xx_i2c_driver = {
17162306a36Sopenharmony_ci	.driver = {
17262306a36Sopenharmony_ci		.name = "rk8xx-i2c",
17362306a36Sopenharmony_ci		.of_match_table = rk8xx_i2c_of_match,
17462306a36Sopenharmony_ci		.pm = &rk8xx_i2c_pm_ops,
17562306a36Sopenharmony_ci	},
17662306a36Sopenharmony_ci	.probe = rk8xx_i2c_probe,
17762306a36Sopenharmony_ci	.shutdown  = rk8xx_i2c_shutdown,
17862306a36Sopenharmony_ci};
17962306a36Sopenharmony_cimodule_i2c_driver(rk8xx_i2c_driver);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
18262306a36Sopenharmony_ciMODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
18362306a36Sopenharmony_ciMODULE_AUTHOR("Zhang Qing <zhangqing@rock-chips.com>");
18462306a36Sopenharmony_ciMODULE_AUTHOR("Wadim Egorov <w.egorov@phytec.de>");
18562306a36Sopenharmony_ciMODULE_DESCRIPTION("RK8xx I2C PMIC driver");
186