18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * isl6271a-regulator.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Support for Intersil ISL6271A voltage regulator 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 98c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License as 108c2ecf20Sopenharmony_ci * published by the Free Software Foundation version 2. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, 138c2ecf20Sopenharmony_ci * whether express or implied; without even the implied warranty of 148c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 158c2ecf20Sopenharmony_ci * General Public License for more details. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/kernel.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/init.h> 218c2ecf20Sopenharmony_ci#include <linux/err.h> 228c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 238c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h> 248c2ecf20Sopenharmony_ci#include <linux/i2c.h> 258c2ecf20Sopenharmony_ci#include <linux/slab.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define ISL6271A_VOLTAGE_MIN 850000 288c2ecf20Sopenharmony_ci#define ISL6271A_VOLTAGE_MAX 1600000 298c2ecf20Sopenharmony_ci#define ISL6271A_VOLTAGE_STEP 50000 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* PMIC details */ 328c2ecf20Sopenharmony_cistruct isl_pmic { 338c2ecf20Sopenharmony_ci struct i2c_client *client; 348c2ecf20Sopenharmony_ci struct mutex mtx; 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int isl6271a_get_voltage_sel(struct regulator_dev *dev) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci struct isl_pmic *pmic = rdev_get_drvdata(dev); 408c2ecf20Sopenharmony_ci int idx; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci mutex_lock(&pmic->mtx); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci idx = i2c_smbus_read_byte(pmic->client); 458c2ecf20Sopenharmony_ci if (idx < 0) 468c2ecf20Sopenharmony_ci dev_err(&pmic->client->dev, "Error getting voltage\n"); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci mutex_unlock(&pmic->mtx); 498c2ecf20Sopenharmony_ci return idx; 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic int isl6271a_set_voltage_sel(struct regulator_dev *dev, 538c2ecf20Sopenharmony_ci unsigned selector) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct isl_pmic *pmic = rdev_get_drvdata(dev); 568c2ecf20Sopenharmony_ci int err; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci mutex_lock(&pmic->mtx); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci err = i2c_smbus_write_byte(pmic->client, selector); 618c2ecf20Sopenharmony_ci if (err < 0) 628c2ecf20Sopenharmony_ci dev_err(&pmic->client->dev, "Error setting voltage\n"); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci mutex_unlock(&pmic->mtx); 658c2ecf20Sopenharmony_ci return err; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic const struct regulator_ops isl_core_ops = { 698c2ecf20Sopenharmony_ci .get_voltage_sel = isl6271a_get_voltage_sel, 708c2ecf20Sopenharmony_ci .set_voltage_sel = isl6271a_set_voltage_sel, 718c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 728c2ecf20Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic const struct regulator_ops isl_fixed_ops = { 768c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic const struct regulator_desc isl_rd[] = { 808c2ecf20Sopenharmony_ci { 818c2ecf20Sopenharmony_ci .name = "Core Buck", 828c2ecf20Sopenharmony_ci .id = 0, 838c2ecf20Sopenharmony_ci .n_voltages = 16, 848c2ecf20Sopenharmony_ci .ops = &isl_core_ops, 858c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, 868c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 878c2ecf20Sopenharmony_ci .min_uV = ISL6271A_VOLTAGE_MIN, 888c2ecf20Sopenharmony_ci .uV_step = ISL6271A_VOLTAGE_STEP, 898c2ecf20Sopenharmony_ci }, { 908c2ecf20Sopenharmony_ci .name = "LDO1", 918c2ecf20Sopenharmony_ci .id = 1, 928c2ecf20Sopenharmony_ci .n_voltages = 1, 938c2ecf20Sopenharmony_ci .ops = &isl_fixed_ops, 948c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, 958c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 968c2ecf20Sopenharmony_ci .min_uV = 1100000, 978c2ecf20Sopenharmony_ci }, { 988c2ecf20Sopenharmony_ci .name = "LDO2", 998c2ecf20Sopenharmony_ci .id = 2, 1008c2ecf20Sopenharmony_ci .n_voltages = 1, 1018c2ecf20Sopenharmony_ci .ops = &isl_fixed_ops, 1028c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, 1038c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1048c2ecf20Sopenharmony_ci .min_uV = 1300000, 1058c2ecf20Sopenharmony_ci }, 1068c2ecf20Sopenharmony_ci}; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic int isl6271a_probe(struct i2c_client *i2c, 1098c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct regulator_dev *rdev; 1128c2ecf20Sopenharmony_ci struct regulator_config config = { }; 1138c2ecf20Sopenharmony_ci struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev); 1148c2ecf20Sopenharmony_ci struct isl_pmic *pmic; 1158c2ecf20Sopenharmony_ci int i; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 1188c2ecf20Sopenharmony_ci return -EIO; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci pmic = devm_kzalloc(&i2c->dev, sizeof(struct isl_pmic), GFP_KERNEL); 1218c2ecf20Sopenharmony_ci if (!pmic) 1228c2ecf20Sopenharmony_ci return -ENOMEM; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci pmic->client = i2c; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci mutex_init(&pmic->mtx); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 1298c2ecf20Sopenharmony_ci config.dev = &i2c->dev; 1308c2ecf20Sopenharmony_ci if (i == 0) 1318c2ecf20Sopenharmony_ci config.init_data = init_data; 1328c2ecf20Sopenharmony_ci else 1338c2ecf20Sopenharmony_ci config.init_data = NULL; 1348c2ecf20Sopenharmony_ci config.driver_data = pmic; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci rdev = devm_regulator_register(&i2c->dev, &isl_rd[i], &config); 1378c2ecf20Sopenharmony_ci if (IS_ERR(rdev)) { 1388c2ecf20Sopenharmony_ci dev_err(&i2c->dev, "failed to register %s\n", id->name); 1398c2ecf20Sopenharmony_ci return PTR_ERR(rdev); 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci i2c_set_clientdata(i2c, pmic); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci return 0; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic const struct i2c_device_id isl6271a_id[] = { 1498c2ecf20Sopenharmony_ci {.name = "isl6271a", 0 }, 1508c2ecf20Sopenharmony_ci { }, 1518c2ecf20Sopenharmony_ci}; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, isl6271a_id); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic struct i2c_driver isl6271a_i2c_driver = { 1568c2ecf20Sopenharmony_ci .driver = { 1578c2ecf20Sopenharmony_ci .name = "isl6271a", 1588c2ecf20Sopenharmony_ci }, 1598c2ecf20Sopenharmony_ci .probe = isl6271a_probe, 1608c2ecf20Sopenharmony_ci .id_table = isl6271a_id, 1618c2ecf20Sopenharmony_ci}; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic int __init isl6271a_init(void) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci return i2c_add_driver(&isl6271a_i2c_driver); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic void __exit isl6271a_cleanup(void) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci i2c_del_driver(&isl6271a_i2c_driver); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cisubsys_initcall(isl6271a_init); 1748c2ecf20Sopenharmony_cimodule_exit(isl6271a_cleanup); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ciMODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); 1778c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Intersil ISL6271A voltage regulator driver"); 1788c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 179