18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 48c2ecf20Sopenharmony_ci#include <linux/i2c.h> 58c2ecf20Sopenharmony_ci#include <linux/kernel.h> 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <linux/of.h> 88c2ecf20Sopenharmony_ci#include <linux/regmap.h> 98c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define RT4801_REG_VOP 0x00 128c2ecf20Sopenharmony_ci#define RT4801_REG_VON 0x01 138c2ecf20Sopenharmony_ci#define RT4801_REG_APPS 0x03 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define VOUT_MASK 0x1F 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define MIN_UV 4000000 188c2ecf20Sopenharmony_ci#define STEP_UV 100000 198c2ecf20Sopenharmony_ci#define MAX_UV 6000000 208c2ecf20Sopenharmony_ci#define N_VOLTAGES ((MAX_UV - MIN_UV) / STEP_UV + 1) 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define DSV_OUT_POS 0 238c2ecf20Sopenharmony_ci#define DSV_OUT_NEG 1 248c2ecf20Sopenharmony_ci#define DSV_OUT_MAX 2 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define DSVP_ENABLE BIT(0) 278c2ecf20Sopenharmony_ci#define DSVN_ENABLE BIT(1) 288c2ecf20Sopenharmony_ci#define DSVALL_ENABLE (DSVP_ENABLE | DSVN_ENABLE) 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistruct rt4801_priv { 318c2ecf20Sopenharmony_ci struct device *dev; 328c2ecf20Sopenharmony_ci struct gpio_descs *enable_gpios; 338c2ecf20Sopenharmony_ci unsigned int enable_flag; 348c2ecf20Sopenharmony_ci unsigned int volt_sel[DSV_OUT_MAX]; 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int rt4801_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci struct rt4801_priv *priv = rdev_get_drvdata(rdev); 408c2ecf20Sopenharmony_ci int id = rdev_get_id(rdev), ret; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci if (priv->enable_flag & BIT(id)) { 438c2ecf20Sopenharmony_ci ret = regulator_set_voltage_sel_regmap(rdev, selector); 448c2ecf20Sopenharmony_ci if (ret) 458c2ecf20Sopenharmony_ci return ret; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci priv->volt_sel[id] = selector; 498c2ecf20Sopenharmony_ci return 0; 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic int rt4801_get_voltage_sel(struct regulator_dev *rdev) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci struct rt4801_priv *priv = rdev_get_drvdata(rdev); 558c2ecf20Sopenharmony_ci int id = rdev_get_id(rdev); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (priv->enable_flag & BIT(id)) 588c2ecf20Sopenharmony_ci return regulator_get_voltage_sel_regmap(rdev); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci return priv->volt_sel[id]; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic int rt4801_enable(struct regulator_dev *rdev) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci struct rt4801_priv *priv = rdev_get_drvdata(rdev); 668c2ecf20Sopenharmony_ci struct gpio_descs *gpios = priv->enable_gpios; 678c2ecf20Sopenharmony_ci int id = rdev_get_id(rdev), ret; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (!gpios || gpios->ndescs <= id) { 708c2ecf20Sopenharmony_ci dev_warn(&rdev->dev, "no dedicated gpio can control\n"); 718c2ecf20Sopenharmony_ci goto bypass_gpio; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci gpiod_set_value(gpios->desc[id], 1); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cibypass_gpio: 778c2ecf20Sopenharmony_ci ret = regmap_write(rdev->regmap, rdev->desc->vsel_reg, priv->volt_sel[id]); 788c2ecf20Sopenharmony_ci if (ret) 798c2ecf20Sopenharmony_ci return ret; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci priv->enable_flag |= BIT(id); 828c2ecf20Sopenharmony_ci return 0; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic int rt4801_disable(struct regulator_dev *rdev) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct rt4801_priv *priv = rdev_get_drvdata(rdev); 888c2ecf20Sopenharmony_ci struct gpio_descs *gpios = priv->enable_gpios; 898c2ecf20Sopenharmony_ci int id = rdev_get_id(rdev); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (!gpios || gpios->ndescs <= id) { 928c2ecf20Sopenharmony_ci dev_warn(&rdev->dev, "no dedicated gpio can control\n"); 938c2ecf20Sopenharmony_ci goto bypass_gpio; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci gpiod_set_value(gpios->desc[id], 0); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cibypass_gpio: 998c2ecf20Sopenharmony_ci priv->enable_flag &= ~BIT(id); 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int rt4801_is_enabled(struct regulator_dev *rdev) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct rt4801_priv *priv = rdev_get_drvdata(rdev); 1068c2ecf20Sopenharmony_ci int id = rdev_get_id(rdev); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci return !!(priv->enable_flag & BIT(id)); 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic const struct regulator_ops rt4801_regulator_ops = { 1128c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 1138c2ecf20Sopenharmony_ci .set_voltage_sel = rt4801_set_voltage_sel, 1148c2ecf20Sopenharmony_ci .get_voltage_sel = rt4801_get_voltage_sel, 1158c2ecf20Sopenharmony_ci .enable = rt4801_enable, 1168c2ecf20Sopenharmony_ci .disable = rt4801_disable, 1178c2ecf20Sopenharmony_ci .is_enabled = rt4801_is_enabled, 1188c2ecf20Sopenharmony_ci}; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic const struct regulator_desc rt4801_regulator_descs[] = { 1218c2ecf20Sopenharmony_ci { 1228c2ecf20Sopenharmony_ci .name = "DSVP", 1238c2ecf20Sopenharmony_ci .ops = &rt4801_regulator_ops, 1248c2ecf20Sopenharmony_ci .of_match = of_match_ptr("DSVP"), 1258c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, 1268c2ecf20Sopenharmony_ci .id = DSV_OUT_POS, 1278c2ecf20Sopenharmony_ci .min_uV = MIN_UV, 1288c2ecf20Sopenharmony_ci .uV_step = STEP_UV, 1298c2ecf20Sopenharmony_ci .n_voltages = N_VOLTAGES, 1308c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1318c2ecf20Sopenharmony_ci .vsel_reg = RT4801_REG_VOP, 1328c2ecf20Sopenharmony_ci .vsel_mask = VOUT_MASK, 1338c2ecf20Sopenharmony_ci }, 1348c2ecf20Sopenharmony_ci { 1358c2ecf20Sopenharmony_ci .name = "DSVN", 1368c2ecf20Sopenharmony_ci .ops = &rt4801_regulator_ops, 1378c2ecf20Sopenharmony_ci .of_match = of_match_ptr("DSVN"), 1388c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, 1398c2ecf20Sopenharmony_ci .id = DSV_OUT_NEG, 1408c2ecf20Sopenharmony_ci .min_uV = MIN_UV, 1418c2ecf20Sopenharmony_ci .uV_step = STEP_UV, 1428c2ecf20Sopenharmony_ci .n_voltages = N_VOLTAGES, 1438c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1448c2ecf20Sopenharmony_ci .vsel_reg = RT4801_REG_VON, 1458c2ecf20Sopenharmony_ci .vsel_mask = VOUT_MASK, 1468c2ecf20Sopenharmony_ci }, 1478c2ecf20Sopenharmony_ci}; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic const struct regmap_config rt4801_regmap_config = { 1508c2ecf20Sopenharmony_ci .reg_bits = 8, 1518c2ecf20Sopenharmony_ci .val_bits = 8, 1528c2ecf20Sopenharmony_ci .max_register = RT4801_REG_APPS, 1538c2ecf20Sopenharmony_ci}; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int rt4801_probe(struct i2c_client *i2c) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci struct rt4801_priv *priv; 1588c2ecf20Sopenharmony_ci struct regmap *regmap; 1598c2ecf20Sopenharmony_ci int i; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); 1628c2ecf20Sopenharmony_ci if (!priv) 1638c2ecf20Sopenharmony_ci return -ENOMEM; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci priv->dev = &i2c->dev; 1668c2ecf20Sopenharmony_ci /* bootloader will on, driver only reconfigure enable to all output high */ 1678c2ecf20Sopenharmony_ci priv->enable_flag = DSVALL_ENABLE; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci regmap = devm_regmap_init_i2c(i2c, &rt4801_regmap_config); 1708c2ecf20Sopenharmony_ci if (IS_ERR(regmap)) { 1718c2ecf20Sopenharmony_ci dev_err(&i2c->dev, "Failed to init regmap\n"); 1728c2ecf20Sopenharmony_ci return PTR_ERR(regmap); 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci priv->enable_gpios = devm_gpiod_get_array_optional(&i2c->dev, "enable", GPIOD_OUT_HIGH); 1768c2ecf20Sopenharmony_ci if (IS_ERR(priv->enable_gpios)) { 1778c2ecf20Sopenharmony_ci dev_err(&i2c->dev, "Failed to get gpios\n"); 1788c2ecf20Sopenharmony_ci return PTR_ERR(priv->enable_gpios); 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci for (i = 0; i < DSV_OUT_MAX; i++) { 1828c2ecf20Sopenharmony_ci const struct regulator_desc *desc = rt4801_regulator_descs + i; 1838c2ecf20Sopenharmony_ci struct regulator_config config = { .dev = &i2c->dev, .driver_data = priv, 1848c2ecf20Sopenharmony_ci .regmap = regmap, }; 1858c2ecf20Sopenharmony_ci struct regulator_dev *rdev; 1868c2ecf20Sopenharmony_ci unsigned int val; 1878c2ecf20Sopenharmony_ci int ret; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* initialize volt_sel variable */ 1908c2ecf20Sopenharmony_ci ret = regmap_read(regmap, desc->vsel_reg, &val); 1918c2ecf20Sopenharmony_ci if (ret) 1928c2ecf20Sopenharmony_ci return ret; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci priv->volt_sel[i] = val & desc->vsel_mask; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci rdev = devm_regulator_register(&i2c->dev, desc, &config); 1978c2ecf20Sopenharmony_ci if (IS_ERR(rdev)) { 1988c2ecf20Sopenharmony_ci dev_err(&i2c->dev, "Failed to register [%d] regulator\n", i); 1998c2ecf20Sopenharmony_ci return PTR_ERR(rdev); 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return 0; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic const struct of_device_id __maybe_unused rt4801_of_id[] = { 2078c2ecf20Sopenharmony_ci { .compatible = "richtek,rt4801", }, 2088c2ecf20Sopenharmony_ci { }, 2098c2ecf20Sopenharmony_ci}; 2108c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, rt4801_of_id); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic struct i2c_driver rt4801_driver = { 2138c2ecf20Sopenharmony_ci .driver = { 2148c2ecf20Sopenharmony_ci .name = "rt4801", 2158c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(rt4801_of_id), 2168c2ecf20Sopenharmony_ci }, 2178c2ecf20Sopenharmony_ci .probe_new = rt4801_probe, 2188c2ecf20Sopenharmony_ci}; 2198c2ecf20Sopenharmony_cimodule_i2c_driver(rt4801_driver); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ciMODULE_AUTHOR("ChiYuan Hwang <cy_huang@richtek.com>"); 2228c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Richtek RT4801 Display Bias Driver"); 2238c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 224