162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * max8952.c - Voltage and current regulation for the Maxim 8952 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2010 Samsung Electronics 662306a36Sopenharmony_ci * MyungJoo Ham <myungjoo.ham@samsung.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/i2c.h> 1262306a36Sopenharmony_ci#include <linux/err.h> 1362306a36Sopenharmony_ci#include <linux/platform_device.h> 1462306a36Sopenharmony_ci#include <linux/regulator/driver.h> 1562306a36Sopenharmony_ci#include <linux/regulator/max8952.h> 1662306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1762306a36Sopenharmony_ci#include <linux/io.h> 1862306a36Sopenharmony_ci#include <linux/of.h> 1962306a36Sopenharmony_ci#include <linux/regulator/of_regulator.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* Registers */ 2362306a36Sopenharmony_cienum { 2462306a36Sopenharmony_ci MAX8952_REG_MODE0, 2562306a36Sopenharmony_ci MAX8952_REG_MODE1, 2662306a36Sopenharmony_ci MAX8952_REG_MODE2, 2762306a36Sopenharmony_ci MAX8952_REG_MODE3, 2862306a36Sopenharmony_ci MAX8952_REG_CONTROL, 2962306a36Sopenharmony_ci MAX8952_REG_SYNC, 3062306a36Sopenharmony_ci MAX8952_REG_RAMP, 3162306a36Sopenharmony_ci MAX8952_REG_CHIP_ID1, 3262306a36Sopenharmony_ci MAX8952_REG_CHIP_ID2, 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistruct max8952_data { 3662306a36Sopenharmony_ci struct i2c_client *client; 3762306a36Sopenharmony_ci struct max8952_platform_data *pdata; 3862306a36Sopenharmony_ci struct gpio_desc *vid0_gpiod; 3962306a36Sopenharmony_ci struct gpio_desc *vid1_gpiod; 4062306a36Sopenharmony_ci bool vid0; 4162306a36Sopenharmony_ci bool vid1; 4262306a36Sopenharmony_ci}; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic int max8952_read_reg(struct max8952_data *max8952, u8 reg) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci int ret = i2c_smbus_read_byte_data(max8952->client, reg); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (ret > 0) 4962306a36Sopenharmony_ci ret &= 0xff; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci return ret; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic int max8952_write_reg(struct max8952_data *max8952, 5562306a36Sopenharmony_ci u8 reg, u8 value) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci return i2c_smbus_write_byte_data(max8952->client, reg, value); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic int max8952_list_voltage(struct regulator_dev *rdev, 6162306a36Sopenharmony_ci unsigned int selector) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci struct max8952_data *max8952 = rdev_get_drvdata(rdev); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (rdev_get_id(rdev) != 0) 6662306a36Sopenharmony_ci return -EINVAL; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci return (max8952->pdata->dvs_mode[selector] * 10 + 770) * 1000; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic int max8952_get_voltage_sel(struct regulator_dev *rdev) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct max8952_data *max8952 = rdev_get_drvdata(rdev); 7462306a36Sopenharmony_ci u8 vid = 0; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (max8952->vid0) 7762306a36Sopenharmony_ci vid += 1; 7862306a36Sopenharmony_ci if (max8952->vid1) 7962306a36Sopenharmony_ci vid += 2; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci return vid; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic int max8952_set_voltage_sel(struct regulator_dev *rdev, 8562306a36Sopenharmony_ci unsigned selector) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct max8952_data *max8952 = rdev_get_drvdata(rdev); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (!max8952->vid0_gpiod || !max8952->vid1_gpiod) { 9062306a36Sopenharmony_ci /* DVS not supported */ 9162306a36Sopenharmony_ci return -EPERM; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci max8952->vid0 = selector & 0x1; 9562306a36Sopenharmony_ci max8952->vid1 = (selector >> 1) & 0x1; 9662306a36Sopenharmony_ci gpiod_set_value(max8952->vid0_gpiod, max8952->vid0); 9762306a36Sopenharmony_ci gpiod_set_value(max8952->vid1_gpiod, max8952->vid1); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci return 0; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic const struct regulator_ops max8952_ops = { 10362306a36Sopenharmony_ci .list_voltage = max8952_list_voltage, 10462306a36Sopenharmony_ci .get_voltage_sel = max8952_get_voltage_sel, 10562306a36Sopenharmony_ci .set_voltage_sel = max8952_set_voltage_sel, 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic const struct regulator_desc regulator = { 10962306a36Sopenharmony_ci .name = "MAX8952_VOUT", 11062306a36Sopenharmony_ci .id = 0, 11162306a36Sopenharmony_ci .n_voltages = MAX8952_NUM_DVS_MODE, 11262306a36Sopenharmony_ci .ops = &max8952_ops, 11362306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, 11462306a36Sopenharmony_ci .owner = THIS_MODULE, 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#ifdef CONFIG_OF 11862306a36Sopenharmony_cistatic const struct of_device_id max8952_dt_match[] = { 11962306a36Sopenharmony_ci { .compatible = "maxim,max8952" }, 12062306a36Sopenharmony_ci {}, 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, max8952_dt_match); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic struct max8952_platform_data *max8952_parse_dt(struct device *dev) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct max8952_platform_data *pd; 12762306a36Sopenharmony_ci struct device_node *np = dev->of_node; 12862306a36Sopenharmony_ci int ret; 12962306a36Sopenharmony_ci int i; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); 13262306a36Sopenharmony_ci if (!pd) 13362306a36Sopenharmony_ci return NULL; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (of_property_read_u32(np, "max8952,default-mode", &pd->default_mode)) 13662306a36Sopenharmony_ci dev_warn(dev, "Default mode not specified, assuming 0\n"); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci ret = of_property_read_u32_array(np, "max8952,dvs-mode-microvolt", 13962306a36Sopenharmony_ci pd->dvs_mode, ARRAY_SIZE(pd->dvs_mode)); 14062306a36Sopenharmony_ci if (ret) { 14162306a36Sopenharmony_ci dev_err(dev, "max8952,dvs-mode-microvolt property not specified"); 14262306a36Sopenharmony_ci return NULL; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pd->dvs_mode); ++i) { 14662306a36Sopenharmony_ci if (pd->dvs_mode[i] < 770000 || pd->dvs_mode[i] > 1400000) { 14762306a36Sopenharmony_ci dev_err(dev, "DVS voltage %d out of range\n", i); 14862306a36Sopenharmony_ci return NULL; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci pd->dvs_mode[i] = (pd->dvs_mode[i] - 770000) / 10000; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (of_property_read_u32(np, "max8952,sync-freq", &pd->sync_freq)) 15462306a36Sopenharmony_ci dev_warn(dev, "max8952,sync-freq property not specified, defaulting to 26MHz\n"); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (of_property_read_u32(np, "max8952,ramp-speed", &pd->ramp_speed)) 15762306a36Sopenharmony_ci dev_warn(dev, "max8952,ramp-speed property not specified, defaulting to 32mV/us\n"); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci pd->reg_data = of_get_regulator_init_data(dev, np, ®ulator); 16062306a36Sopenharmony_ci if (!pd->reg_data) { 16162306a36Sopenharmony_ci dev_err(dev, "Failed to parse regulator init data\n"); 16262306a36Sopenharmony_ci return NULL; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci return pd; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci#else 16862306a36Sopenharmony_cistatic struct max8952_platform_data *max8952_parse_dt(struct device *dev) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci return NULL; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci#endif 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic int max8952_pmic_probe(struct i2c_client *client) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci struct i2c_adapter *adapter = client->adapter; 17762306a36Sopenharmony_ci struct max8952_platform_data *pdata = dev_get_platdata(&client->dev); 17862306a36Sopenharmony_ci struct regulator_config config = { }; 17962306a36Sopenharmony_ci struct max8952_data *max8952; 18062306a36Sopenharmony_ci struct regulator_dev *rdev; 18162306a36Sopenharmony_ci struct gpio_desc *gpiod; 18262306a36Sopenharmony_ci enum gpiod_flags gflags; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci int ret = 0; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (client->dev.of_node) 18762306a36Sopenharmony_ci pdata = max8952_parse_dt(&client->dev); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (!pdata) { 19062306a36Sopenharmony_ci dev_err(&client->dev, "Require the platform data\n"); 19162306a36Sopenharmony_ci return -EINVAL; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) 19562306a36Sopenharmony_ci return -EIO; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci max8952 = devm_kzalloc(&client->dev, sizeof(struct max8952_data), 19862306a36Sopenharmony_ci GFP_KERNEL); 19962306a36Sopenharmony_ci if (!max8952) 20062306a36Sopenharmony_ci return -ENOMEM; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci max8952->client = client; 20362306a36Sopenharmony_ci max8952->pdata = pdata; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci config.dev = &client->dev; 20662306a36Sopenharmony_ci config.init_data = pdata->reg_data; 20762306a36Sopenharmony_ci config.driver_data = max8952; 20862306a36Sopenharmony_ci config.of_node = client->dev.of_node; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (pdata->reg_data->constraints.boot_on) 21162306a36Sopenharmony_ci gflags = GPIOD_OUT_HIGH; 21262306a36Sopenharmony_ci else 21362306a36Sopenharmony_ci gflags = GPIOD_OUT_LOW; 21462306a36Sopenharmony_ci gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE; 21562306a36Sopenharmony_ci /* 21662306a36Sopenharmony_ci * Do not use devm* here: the regulator core takes over the 21762306a36Sopenharmony_ci * lifecycle management of the GPIO descriptor. 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_ci gpiod = gpiod_get_optional(&client->dev, 22062306a36Sopenharmony_ci "max8952,en", 22162306a36Sopenharmony_ci gflags); 22262306a36Sopenharmony_ci if (IS_ERR(gpiod)) 22362306a36Sopenharmony_ci return PTR_ERR(gpiod); 22462306a36Sopenharmony_ci if (gpiod) 22562306a36Sopenharmony_ci config.ena_gpiod = gpiod; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci rdev = devm_regulator_register(&client->dev, ®ulator, &config); 22862306a36Sopenharmony_ci if (IS_ERR(rdev)) { 22962306a36Sopenharmony_ci ret = PTR_ERR(rdev); 23062306a36Sopenharmony_ci dev_err(&client->dev, "regulator init failed (%d)\n", ret); 23162306a36Sopenharmony_ci return ret; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci max8952->vid0 = pdata->default_mode & 0x1; 23562306a36Sopenharmony_ci max8952->vid1 = (pdata->default_mode >> 1) & 0x1; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* Fetch vid0 and vid1 GPIOs if available */ 23862306a36Sopenharmony_ci gflags = max8952->vid0 ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; 23962306a36Sopenharmony_ci max8952->vid0_gpiod = devm_gpiod_get_index_optional(&client->dev, 24062306a36Sopenharmony_ci "max8952,vid", 24162306a36Sopenharmony_ci 0, gflags); 24262306a36Sopenharmony_ci if (IS_ERR(max8952->vid0_gpiod)) 24362306a36Sopenharmony_ci return PTR_ERR(max8952->vid0_gpiod); 24462306a36Sopenharmony_ci gflags = max8952->vid1 ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; 24562306a36Sopenharmony_ci max8952->vid1_gpiod = devm_gpiod_get_index_optional(&client->dev, 24662306a36Sopenharmony_ci "max8952,vid", 24762306a36Sopenharmony_ci 1, gflags); 24862306a36Sopenharmony_ci if (IS_ERR(max8952->vid1_gpiod)) 24962306a36Sopenharmony_ci return PTR_ERR(max8952->vid1_gpiod); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* If either VID GPIO is missing just disable this */ 25262306a36Sopenharmony_ci if (!max8952->vid0_gpiod || !max8952->vid1_gpiod) { 25362306a36Sopenharmony_ci dev_warn(&client->dev, "VID0/1 gpio invalid: " 25462306a36Sopenharmony_ci "DVS not available.\n"); 25562306a36Sopenharmony_ci max8952->vid0 = 0; 25662306a36Sopenharmony_ci max8952->vid1 = 0; 25762306a36Sopenharmony_ci /* Make sure if we have any descriptors they get set to low */ 25862306a36Sopenharmony_ci if (max8952->vid0_gpiod) 25962306a36Sopenharmony_ci gpiod_set_value(max8952->vid0_gpiod, 0); 26062306a36Sopenharmony_ci if (max8952->vid1_gpiod) 26162306a36Sopenharmony_ci gpiod_set_value(max8952->vid1_gpiod, 0); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* Disable Pulldown of EN only */ 26462306a36Sopenharmony_ci max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x60); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci dev_err(&client->dev, "DVS modes disabled because VID0 and VID1" 26762306a36Sopenharmony_ci " do not have proper controls.\n"); 26862306a36Sopenharmony_ci } else { 26962306a36Sopenharmony_ci /* 27062306a36Sopenharmony_ci * Disable Pulldown on EN, VID0, VID1 to reduce 27162306a36Sopenharmony_ci * leakage current of MAX8952 assuming that MAX8952 27262306a36Sopenharmony_ci * is turned on (EN==1). Note that without having VID0/1 27362306a36Sopenharmony_ci * properly connected, turning pulldown off can be 27462306a36Sopenharmony_ci * problematic. Thus, turn this off only when they are 27562306a36Sopenharmony_ci * controllable by GPIO. 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_ci max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x0); 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci max8952_write_reg(max8952, MAX8952_REG_MODE0, 28162306a36Sopenharmony_ci (max8952_read_reg(max8952, 28262306a36Sopenharmony_ci MAX8952_REG_MODE0) & 0xC0) | 28362306a36Sopenharmony_ci (pdata->dvs_mode[0] & 0x3F)); 28462306a36Sopenharmony_ci max8952_write_reg(max8952, MAX8952_REG_MODE1, 28562306a36Sopenharmony_ci (max8952_read_reg(max8952, 28662306a36Sopenharmony_ci MAX8952_REG_MODE1) & 0xC0) | 28762306a36Sopenharmony_ci (pdata->dvs_mode[1] & 0x3F)); 28862306a36Sopenharmony_ci max8952_write_reg(max8952, MAX8952_REG_MODE2, 28962306a36Sopenharmony_ci (max8952_read_reg(max8952, 29062306a36Sopenharmony_ci MAX8952_REG_MODE2) & 0xC0) | 29162306a36Sopenharmony_ci (pdata->dvs_mode[2] & 0x3F)); 29262306a36Sopenharmony_ci max8952_write_reg(max8952, MAX8952_REG_MODE3, 29362306a36Sopenharmony_ci (max8952_read_reg(max8952, 29462306a36Sopenharmony_ci MAX8952_REG_MODE3) & 0xC0) | 29562306a36Sopenharmony_ci (pdata->dvs_mode[3] & 0x3F)); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci max8952_write_reg(max8952, MAX8952_REG_SYNC, 29862306a36Sopenharmony_ci (max8952_read_reg(max8952, MAX8952_REG_SYNC) & 0x3F) | 29962306a36Sopenharmony_ci ((pdata->sync_freq & 0x3) << 6)); 30062306a36Sopenharmony_ci max8952_write_reg(max8952, MAX8952_REG_RAMP, 30162306a36Sopenharmony_ci (max8952_read_reg(max8952, MAX8952_REG_RAMP) & 0x1F) | 30262306a36Sopenharmony_ci ((pdata->ramp_speed & 0x7) << 5)); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci i2c_set_clientdata(client, max8952); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci return 0; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic const struct i2c_device_id max8952_ids[] = { 31062306a36Sopenharmony_ci { "max8952", 0 }, 31162306a36Sopenharmony_ci { }, 31262306a36Sopenharmony_ci}; 31362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, max8952_ids); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic struct i2c_driver max8952_pmic_driver = { 31662306a36Sopenharmony_ci .probe = max8952_pmic_probe, 31762306a36Sopenharmony_ci .driver = { 31862306a36Sopenharmony_ci .name = "max8952", 31962306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 32062306a36Sopenharmony_ci .of_match_table = of_match_ptr(max8952_dt_match), 32162306a36Sopenharmony_ci }, 32262306a36Sopenharmony_ci .id_table = max8952_ids, 32362306a36Sopenharmony_ci}; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic int __init max8952_pmic_init(void) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci return i2c_add_driver(&max8952_pmic_driver); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_cisubsys_initcall(max8952_pmic_init); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic void __exit max8952_pmic_exit(void) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci i2c_del_driver(&max8952_pmic_driver); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_cimodule_exit(max8952_pmic_exit); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ciMODULE_DESCRIPTION("MAXIM 8952 voltage regulator driver"); 33862306a36Sopenharmony_ciMODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); 33962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 340