18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * max1586.c -- Voltage and current regulation for the Maxim 1586 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2008 Robert Jarzmik 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/module.h> 88c2ecf20Sopenharmony_ci#include <linux/err.h> 98c2ecf20Sopenharmony_ci#include <linux/i2c.h> 108c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 118c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/regulator/max1586.h> 148c2ecf20Sopenharmony_ci#include <linux/of_device.h> 158c2ecf20Sopenharmony_ci#include <linux/regulator/of_regulator.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define MAX1586_V3_MAX_VSEL 31 188c2ecf20Sopenharmony_ci#define MAX1586_V6_MAX_VSEL 3 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define MAX1586_V3_MIN_UV 700000 218c2ecf20Sopenharmony_ci#define MAX1586_V3_MAX_UV 1475000 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define MAX1586_V6_MIN_UV 0 248c2ecf20Sopenharmony_ci#define MAX1586_V6_MAX_UV 3000000 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define I2C_V3_SELECT (0 << 5) 278c2ecf20Sopenharmony_ci#define I2C_V6_SELECT (1 << 5) 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistruct max1586_data { 308c2ecf20Sopenharmony_ci struct i2c_client *client; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci /* min/max V3 voltage */ 338c2ecf20Sopenharmony_ci unsigned int min_uV; 348c2ecf20Sopenharmony_ci unsigned int max_uV; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci unsigned int v3_curr_sel; 378c2ecf20Sopenharmony_ci unsigned int v6_curr_sel; 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* 418c2ecf20Sopenharmony_ci * V6 voltage 428c2ecf20Sopenharmony_ci * On I2C bus, sending a "x" byte to the max1586 means : 438c2ecf20Sopenharmony_ci * set V6 to either 0V, 1.8V, 2.5V, 3V depending on (x & 0x3) 448c2ecf20Sopenharmony_ci * As regulator framework doesn't accept voltages to be 0V, we use 1uV. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_cistatic const unsigned int v6_voltages_uv[] = { 1, 1800000, 2500000, 3000000 }; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* 498c2ecf20Sopenharmony_ci * V3 voltage 508c2ecf20Sopenharmony_ci * On I2C bus, sending a "x" byte to the max1586 means : 518c2ecf20Sopenharmony_ci * set V3 to 0.700V + (x & 0x1f) * 0.025V 528c2ecf20Sopenharmony_ci * This voltage can be increased by external resistors 538c2ecf20Sopenharmony_ci * R24 and R25=100kOhm as described in the data sheet. 548c2ecf20Sopenharmony_ci * The gain is approximately: 1 + R24/R25 + R24/185.5kOhm 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_cistatic int max1586_v3_get_voltage_sel(struct regulator_dev *rdev) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci struct max1586_data *max1586 = rdev_get_drvdata(rdev); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci return max1586->v3_curr_sel; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic int max1586_v3_set_voltage_sel(struct regulator_dev *rdev, 648c2ecf20Sopenharmony_ci unsigned selector) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct max1586_data *max1586 = rdev_get_drvdata(rdev); 678c2ecf20Sopenharmony_ci struct i2c_client *client = max1586->client; 688c2ecf20Sopenharmony_ci int ret; 698c2ecf20Sopenharmony_ci u8 v3_prog; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "changing voltage v3 to %dmv\n", 728c2ecf20Sopenharmony_ci regulator_list_voltage_linear(rdev, selector) / 1000); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci v3_prog = I2C_V3_SELECT | (u8) selector; 758c2ecf20Sopenharmony_ci ret = i2c_smbus_write_byte(client, v3_prog); 768c2ecf20Sopenharmony_ci if (ret) 778c2ecf20Sopenharmony_ci return ret; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci max1586->v3_curr_sel = selector; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci return 0; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int max1586_v6_get_voltage_sel(struct regulator_dev *rdev) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct max1586_data *max1586 = rdev_get_drvdata(rdev); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci return max1586->v6_curr_sel; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int max1586_v6_set_voltage_sel(struct regulator_dev *rdev, 928c2ecf20Sopenharmony_ci unsigned int selector) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci struct max1586_data *max1586 = rdev_get_drvdata(rdev); 958c2ecf20Sopenharmony_ci struct i2c_client *client = max1586->client; 968c2ecf20Sopenharmony_ci u8 v6_prog; 978c2ecf20Sopenharmony_ci int ret; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "changing voltage v6 to %dmv\n", 1008c2ecf20Sopenharmony_ci rdev->desc->volt_table[selector] / 1000); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci v6_prog = I2C_V6_SELECT | (u8) selector; 1038c2ecf20Sopenharmony_ci ret = i2c_smbus_write_byte(client, v6_prog); 1048c2ecf20Sopenharmony_ci if (ret) 1058c2ecf20Sopenharmony_ci return ret; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci max1586->v6_curr_sel = selector; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return 0; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/* 1138c2ecf20Sopenharmony_ci * The Maxim 1586 controls V3 and V6 voltages, but offers no way of reading back 1148c2ecf20Sopenharmony_ci * the set up value. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_cistatic const struct regulator_ops max1586_v3_ops = { 1178c2ecf20Sopenharmony_ci .get_voltage_sel = max1586_v3_get_voltage_sel, 1188c2ecf20Sopenharmony_ci .set_voltage_sel = max1586_v3_set_voltage_sel, 1198c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 1208c2ecf20Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 1218c2ecf20Sopenharmony_ci}; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic const struct regulator_ops max1586_v6_ops = { 1248c2ecf20Sopenharmony_ci .get_voltage_sel = max1586_v6_get_voltage_sel, 1258c2ecf20Sopenharmony_ci .set_voltage_sel = max1586_v6_set_voltage_sel, 1268c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_table, 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic struct regulator_desc max1586_reg[] = { 1308c2ecf20Sopenharmony_ci { 1318c2ecf20Sopenharmony_ci .name = "Output_V3", 1328c2ecf20Sopenharmony_ci .id = MAX1586_V3, 1338c2ecf20Sopenharmony_ci .ops = &max1586_v3_ops, 1348c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, 1358c2ecf20Sopenharmony_ci .n_voltages = MAX1586_V3_MAX_VSEL + 1, 1368c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1378c2ecf20Sopenharmony_ci }, 1388c2ecf20Sopenharmony_ci { 1398c2ecf20Sopenharmony_ci .name = "Output_V6", 1408c2ecf20Sopenharmony_ci .id = MAX1586_V6, 1418c2ecf20Sopenharmony_ci .ops = &max1586_v6_ops, 1428c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, 1438c2ecf20Sopenharmony_ci .n_voltages = MAX1586_V6_MAX_VSEL + 1, 1448c2ecf20Sopenharmony_ci .volt_table = v6_voltages_uv, 1458c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1468c2ecf20Sopenharmony_ci }, 1478c2ecf20Sopenharmony_ci}; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic int of_get_max1586_platform_data(struct device *dev, 1508c2ecf20Sopenharmony_ci struct max1586_platform_data *pdata) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci struct max1586_subdev_data *sub; 1538c2ecf20Sopenharmony_ci struct of_regulator_match rmatch[ARRAY_SIZE(max1586_reg)] = { }; 1548c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 1558c2ecf20Sopenharmony_ci int i, matched; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "v3-gain", 1588c2ecf20Sopenharmony_ci &pdata->v3_gain) < 0) { 1598c2ecf20Sopenharmony_ci dev_err(dev, "%pOF has no 'v3-gain' property\n", np); 1608c2ecf20Sopenharmony_ci return -EINVAL; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci np = of_get_child_by_name(np, "regulators"); 1648c2ecf20Sopenharmony_ci if (!np) { 1658c2ecf20Sopenharmony_ci dev_err(dev, "missing 'regulators' subnode in DT\n"); 1668c2ecf20Sopenharmony_ci return -EINVAL; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rmatch); i++) 1708c2ecf20Sopenharmony_ci rmatch[i].name = max1586_reg[i].name; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci matched = of_regulator_match(dev, np, rmatch, ARRAY_SIZE(rmatch)); 1738c2ecf20Sopenharmony_ci of_node_put(np); 1748c2ecf20Sopenharmony_ci /* 1758c2ecf20Sopenharmony_ci * If matched is 0, ie. neither Output_V3 nor Output_V6 have been found, 1768c2ecf20Sopenharmony_ci * return 0, which signals the normal situation where no subregulator is 1778c2ecf20Sopenharmony_ci * available. This is normal because the max1586 doesn't provide any 1788c2ecf20Sopenharmony_ci * readback support, so the subregulators can't report any status 1798c2ecf20Sopenharmony_ci * anyway. If matched < 0, return the error. 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_ci if (matched <= 0) 1828c2ecf20Sopenharmony_ci return matched; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci pdata->subdevs = devm_kcalloc(dev, 1858c2ecf20Sopenharmony_ci matched, 1868c2ecf20Sopenharmony_ci sizeof(struct max1586_subdev_data), 1878c2ecf20Sopenharmony_ci GFP_KERNEL); 1888c2ecf20Sopenharmony_ci if (!pdata->subdevs) 1898c2ecf20Sopenharmony_ci return -ENOMEM; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci pdata->num_subdevs = matched; 1928c2ecf20Sopenharmony_ci sub = pdata->subdevs; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci for (i = 0; i < matched; i++) { 1958c2ecf20Sopenharmony_ci sub->id = i; 1968c2ecf20Sopenharmony_ci sub->name = rmatch[i].of_node->name; 1978c2ecf20Sopenharmony_ci sub->platform_data = rmatch[i].init_data; 1988c2ecf20Sopenharmony_ci sub++; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci return 0; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic const struct of_device_id __maybe_unused max1586_of_match[] = { 2058c2ecf20Sopenharmony_ci { .compatible = "maxim,max1586", }, 2068c2ecf20Sopenharmony_ci {}, 2078c2ecf20Sopenharmony_ci}; 2088c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, max1586_of_match); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic int max1586_pmic_probe(struct i2c_client *client, 2118c2ecf20Sopenharmony_ci const struct i2c_device_id *i2c_id) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct max1586_platform_data *pdata, pdata_of; 2148c2ecf20Sopenharmony_ci struct regulator_config config = { }; 2158c2ecf20Sopenharmony_ci struct max1586_data *max1586; 2168c2ecf20Sopenharmony_ci int i, id, ret; 2178c2ecf20Sopenharmony_ci const struct of_device_id *match; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci pdata = dev_get_platdata(&client->dev); 2208c2ecf20Sopenharmony_ci if (client->dev.of_node && !pdata) { 2218c2ecf20Sopenharmony_ci match = of_match_device(of_match_ptr(max1586_of_match), 2228c2ecf20Sopenharmony_ci &client->dev); 2238c2ecf20Sopenharmony_ci if (!match) { 2248c2ecf20Sopenharmony_ci dev_err(&client->dev, "Error: No device match found\n"); 2258c2ecf20Sopenharmony_ci return -ENODEV; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci ret = of_get_max1586_platform_data(&client->dev, &pdata_of); 2288c2ecf20Sopenharmony_ci if (ret < 0) 2298c2ecf20Sopenharmony_ci return ret; 2308c2ecf20Sopenharmony_ci pdata = &pdata_of; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci max1586 = devm_kzalloc(&client->dev, sizeof(struct max1586_data), 2348c2ecf20Sopenharmony_ci GFP_KERNEL); 2358c2ecf20Sopenharmony_ci if (!max1586) 2368c2ecf20Sopenharmony_ci return -ENOMEM; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci max1586->client = client; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (!pdata->v3_gain) 2418c2ecf20Sopenharmony_ci return -EINVAL; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci max1586->min_uV = MAX1586_V3_MIN_UV / 1000 * pdata->v3_gain / 1000; 2448c2ecf20Sopenharmony_ci max1586->max_uV = MAX1586_V3_MAX_UV / 1000 * pdata->v3_gain / 1000; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* Set curr_sel to default voltage on power-up */ 2478c2ecf20Sopenharmony_ci max1586->v3_curr_sel = 24; /* 1.3V */ 2488c2ecf20Sopenharmony_ci max1586->v6_curr_sel = 0; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci for (i = 0; i < pdata->num_subdevs && i <= MAX1586_V6; i++) { 2518c2ecf20Sopenharmony_ci struct regulator_dev *rdev; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci id = pdata->subdevs[i].id; 2548c2ecf20Sopenharmony_ci if (!pdata->subdevs[i].platform_data) 2558c2ecf20Sopenharmony_ci continue; 2568c2ecf20Sopenharmony_ci if (id < MAX1586_V3 || id > MAX1586_V6) { 2578c2ecf20Sopenharmony_ci dev_err(&client->dev, "invalid regulator id %d\n", id); 2588c2ecf20Sopenharmony_ci return -EINVAL; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (id == MAX1586_V3) { 2628c2ecf20Sopenharmony_ci max1586_reg[id].min_uV = max1586->min_uV; 2638c2ecf20Sopenharmony_ci max1586_reg[id].uV_step = 2648c2ecf20Sopenharmony_ci (max1586->max_uV - max1586->min_uV) / 2658c2ecf20Sopenharmony_ci MAX1586_V3_MAX_VSEL; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci config.dev = &client->dev; 2698c2ecf20Sopenharmony_ci config.init_data = pdata->subdevs[i].platform_data; 2708c2ecf20Sopenharmony_ci config.driver_data = max1586; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci rdev = devm_regulator_register(&client->dev, 2738c2ecf20Sopenharmony_ci &max1586_reg[id], &config); 2748c2ecf20Sopenharmony_ci if (IS_ERR(rdev)) { 2758c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to register %s\n", 2768c2ecf20Sopenharmony_ci max1586_reg[id].name); 2778c2ecf20Sopenharmony_ci return PTR_ERR(rdev); 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci i2c_set_clientdata(client, max1586); 2828c2ecf20Sopenharmony_ci dev_info(&client->dev, "Maxim 1586 regulator driver loaded\n"); 2838c2ecf20Sopenharmony_ci return 0; 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic const struct i2c_device_id max1586_id[] = { 2878c2ecf20Sopenharmony_ci { "max1586", 0 }, 2888c2ecf20Sopenharmony_ci { } 2898c2ecf20Sopenharmony_ci}; 2908c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, max1586_id); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic struct i2c_driver max1586_pmic_driver = { 2938c2ecf20Sopenharmony_ci .probe = max1586_pmic_probe, 2948c2ecf20Sopenharmony_ci .driver = { 2958c2ecf20Sopenharmony_ci .name = "max1586", 2968c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(max1586_of_match), 2978c2ecf20Sopenharmony_ci }, 2988c2ecf20Sopenharmony_ci .id_table = max1586_id, 2998c2ecf20Sopenharmony_ci}; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic int __init max1586_pmic_init(void) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci return i2c_add_driver(&max1586_pmic_driver); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_cisubsys_initcall(max1586_pmic_init); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic void __exit max1586_pmic_exit(void) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci i2c_del_driver(&max1586_pmic_driver); 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_cimodule_exit(max1586_pmic_exit); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci/* Module information */ 3148c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MAXIM 1586 voltage regulator driver"); 3158c2ecf20Sopenharmony_ciMODULE_AUTHOR("Robert Jarzmik"); 3168c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 317