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