172 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * isl6271a-regulator.c4 *5 * Support for Intersil ISL6271A voltage regulator6 *7 * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>8 */9 10#include <linux/kernel.h>11#include <linux/module.h>12#include <linux/init.h>13#include <linux/err.h>14#include <linux/platform_device.h>15#include <linux/regulator/driver.h>16#include <linux/i2c.h>17#include <linux/slab.h>18 19#define ISL6271A_VOLTAGE_MIN 85000020#define ISL6271A_VOLTAGE_MAX 160000021#define ISL6271A_VOLTAGE_STEP 5000022 23/* PMIC details */24struct isl_pmic {25 struct i2c_client *client;26 struct mutex mtx;27};28 29static int isl6271a_get_voltage_sel(struct regulator_dev *dev)30{31 struct isl_pmic *pmic = rdev_get_drvdata(dev);32 int idx;33 34 mutex_lock(&pmic->mtx);35 36 idx = i2c_smbus_read_byte(pmic->client);37 if (idx < 0)38 dev_err(&pmic->client->dev, "Error getting voltage\n");39 40 mutex_unlock(&pmic->mtx);41 return idx;42}43 44static int isl6271a_set_voltage_sel(struct regulator_dev *dev,45 unsigned selector)46{47 struct isl_pmic *pmic = rdev_get_drvdata(dev);48 int err;49 50 mutex_lock(&pmic->mtx);51 52 err = i2c_smbus_write_byte(pmic->client, selector);53 if (err < 0)54 dev_err(&pmic->client->dev, "Error setting voltage\n");55 56 mutex_unlock(&pmic->mtx);57 return err;58}59 60static const struct regulator_ops isl_core_ops = {61 .get_voltage_sel = isl6271a_get_voltage_sel,62 .set_voltage_sel = isl6271a_set_voltage_sel,63 .list_voltage = regulator_list_voltage_linear,64 .map_voltage = regulator_map_voltage_linear,65};66 67static const struct regulator_ops isl_fixed_ops = {68 .list_voltage = regulator_list_voltage_linear,69};70 71static const struct regulator_desc isl_rd[] = {72 {73 .name = "Core Buck",74 .id = 0,75 .n_voltages = 16,76 .ops = &isl_core_ops,77 .type = REGULATOR_VOLTAGE,78 .owner = THIS_MODULE,79 .min_uV = ISL6271A_VOLTAGE_MIN,80 .uV_step = ISL6271A_VOLTAGE_STEP,81 }, {82 .name = "LDO1",83 .id = 1,84 .n_voltages = 1,85 .ops = &isl_fixed_ops,86 .type = REGULATOR_VOLTAGE,87 .owner = THIS_MODULE,88 .min_uV = 1100000,89 }, {90 .name = "LDO2",91 .id = 2,92 .n_voltages = 1,93 .ops = &isl_fixed_ops,94 .type = REGULATOR_VOLTAGE,95 .owner = THIS_MODULE,96 .min_uV = 1300000,97 },98};99 100static int isl6271a_probe(struct i2c_client *i2c)101{102 const struct i2c_device_id *id = i2c_client_get_device_id(i2c);103 struct regulator_dev *rdev;104 struct regulator_config config = { };105 struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev);106 struct isl_pmic *pmic;107 int i;108 109 if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))110 return -EIO;111 112 pmic = devm_kzalloc(&i2c->dev, sizeof(struct isl_pmic), GFP_KERNEL);113 if (!pmic)114 return -ENOMEM;115 116 pmic->client = i2c;117 118 mutex_init(&pmic->mtx);119 120 for (i = 0; i < 3; i++) {121 config.dev = &i2c->dev;122 if (i == 0)123 config.init_data = init_data;124 else125 config.init_data = NULL;126 config.driver_data = pmic;127 128 rdev = devm_regulator_register(&i2c->dev, &isl_rd[i], &config);129 if (IS_ERR(rdev)) {130 dev_err(&i2c->dev, "failed to register %s\n", id->name);131 return PTR_ERR(rdev);132 }133 }134 135 i2c_set_clientdata(i2c, pmic);136 137 return 0;138}139 140static const struct i2c_device_id isl6271a_id[] = {141 {.name = "isl6271a", 0 },142 { },143};144 145MODULE_DEVICE_TABLE(i2c, isl6271a_id);146 147static struct i2c_driver isl6271a_i2c_driver = {148 .driver = {149 .name = "isl6271a",150 .probe_type = PROBE_PREFER_ASYNCHRONOUS,151 },152 .probe = isl6271a_probe,153 .id_table = isl6271a_id,154};155 156static int __init isl6271a_init(void)157{158 return i2c_add_driver(&isl6271a_i2c_driver);159}160 161static void __exit isl6271a_cleanup(void)162{163 i2c_del_driver(&isl6271a_i2c_driver);164}165 166subsys_initcall(isl6271a_init);167module_exit(isl6271a_cleanup);168 169MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");170MODULE_DESCRIPTION("Intersil ISL6271A voltage regulator driver");171MODULE_LICENSE("GPL v2");172