202 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * linux/drivers/regulator/aat2870-regulator.c4 *5 * Copyright (c) 2011, NVIDIA Corporation.6 * Author: Jin Park <jinyoungp@nvidia.com>7 */8 9#include <linux/kernel.h>10#include <linux/init.h>11#include <linux/err.h>12#include <linux/module.h>13#include <linux/slab.h>14#include <linux/platform_device.h>15#include <linux/regulator/driver.h>16#include <linux/regulator/machine.h>17#include <linux/mfd/aat2870.h>18 19struct aat2870_regulator {20 struct aat2870_data *aat2870;21 struct regulator_desc desc;22 23 u8 enable_addr;24 u8 enable_shift;25 u8 enable_mask;26 27 u8 voltage_addr;28 u8 voltage_shift;29 u8 voltage_mask;30};31 32static int aat2870_ldo_set_voltage_sel(struct regulator_dev *rdev,33 unsigned selector)34{35 struct aat2870_regulator *ri = rdev_get_drvdata(rdev);36 struct aat2870_data *aat2870 = ri->aat2870;37 38 return aat2870->update(aat2870, ri->voltage_addr, ri->voltage_mask,39 selector << ri->voltage_shift);40}41 42static int aat2870_ldo_get_voltage_sel(struct regulator_dev *rdev)43{44 struct aat2870_regulator *ri = rdev_get_drvdata(rdev);45 struct aat2870_data *aat2870 = ri->aat2870;46 u8 val;47 int ret;48 49 ret = aat2870->read(aat2870, ri->voltage_addr, &val);50 if (ret)51 return ret;52 53 return (val & ri->voltage_mask) >> ri->voltage_shift;54}55 56static int aat2870_ldo_enable(struct regulator_dev *rdev)57{58 struct aat2870_regulator *ri = rdev_get_drvdata(rdev);59 struct aat2870_data *aat2870 = ri->aat2870;60 61 return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask,62 ri->enable_mask);63}64 65static int aat2870_ldo_disable(struct regulator_dev *rdev)66{67 struct aat2870_regulator *ri = rdev_get_drvdata(rdev);68 struct aat2870_data *aat2870 = ri->aat2870;69 70 return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask, 0);71}72 73static int aat2870_ldo_is_enabled(struct regulator_dev *rdev)74{75 struct aat2870_regulator *ri = rdev_get_drvdata(rdev);76 struct aat2870_data *aat2870 = ri->aat2870;77 u8 val;78 int ret;79 80 ret = aat2870->read(aat2870, ri->enable_addr, &val);81 if (ret)82 return ret;83 84 return val & ri->enable_mask ? 1 : 0;85}86 87static const struct regulator_ops aat2870_ldo_ops = {88 .list_voltage = regulator_list_voltage_table,89 .map_voltage = regulator_map_voltage_ascend,90 .set_voltage_sel = aat2870_ldo_set_voltage_sel,91 .get_voltage_sel = aat2870_ldo_get_voltage_sel,92 .enable = aat2870_ldo_enable,93 .disable = aat2870_ldo_disable,94 .is_enabled = aat2870_ldo_is_enabled,95};96 97static const unsigned int aat2870_ldo_voltages[] = {98 1200000, 1300000, 1500000, 1600000,99 1800000, 2000000, 2200000, 2500000,100 2600000, 2700000, 2800000, 2900000,101 3000000, 3100000, 3200000, 3300000,102};103 104#define AAT2870_LDO(ids) \105 { \106 .desc = { \107 .name = #ids, \108 .id = AAT2870_ID_##ids, \109 .n_voltages = ARRAY_SIZE(aat2870_ldo_voltages), \110 .volt_table = aat2870_ldo_voltages, \111 .ops = &aat2870_ldo_ops, \112 .type = REGULATOR_VOLTAGE, \113 .owner = THIS_MODULE, \114 }, \115 }116 117static struct aat2870_regulator aat2870_regulators[] = {118 AAT2870_LDO(LDOA),119 AAT2870_LDO(LDOB),120 AAT2870_LDO(LDOC),121 AAT2870_LDO(LDOD),122};123 124static struct aat2870_regulator *aat2870_get_regulator(int id)125{126 struct aat2870_regulator *ri = NULL;127 int i;128 129 for (i = 0; i < ARRAY_SIZE(aat2870_regulators); i++) {130 ri = &aat2870_regulators[i];131 if (ri->desc.id == id)132 break;133 }134 135 if (i == ARRAY_SIZE(aat2870_regulators))136 return NULL;137 138 ri->enable_addr = AAT2870_LDO_EN;139 ri->enable_shift = id - AAT2870_ID_LDOA;140 ri->enable_mask = 0x1 << ri->enable_shift;141 142 ri->voltage_addr = (id - AAT2870_ID_LDOA) / 2 ?143 AAT2870_LDO_CD : AAT2870_LDO_AB;144 ri->voltage_shift = (id - AAT2870_ID_LDOA) % 2 ? 0 : 4;145 ri->voltage_mask = 0xF << ri->voltage_shift;146 147 return ri;148}149 150static int aat2870_regulator_probe(struct platform_device *pdev)151{152 struct aat2870_regulator *ri;153 struct regulator_config config = { };154 struct regulator_dev *rdev;155 156 ri = aat2870_get_regulator(pdev->id);157 if (!ri) {158 dev_err(&pdev->dev, "Invalid device ID, %d\n", pdev->id);159 return -EINVAL;160 }161 ri->aat2870 = dev_get_drvdata(pdev->dev.parent);162 163 config.dev = &pdev->dev;164 config.driver_data = ri;165 config.init_data = dev_get_platdata(&pdev->dev);166 167 rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config);168 if (IS_ERR(rdev)) {169 dev_err(&pdev->dev, "Failed to register regulator %s\n",170 ri->desc.name);171 return PTR_ERR(rdev);172 }173 platform_set_drvdata(pdev, rdev);174 175 return 0;176}177 178static struct platform_driver aat2870_regulator_driver = {179 .driver = {180 .name = "aat2870-regulator",181 .probe_type = PROBE_PREFER_ASYNCHRONOUS,182 },183 .probe = aat2870_regulator_probe,184};185 186static int __init aat2870_regulator_init(void)187{188 return platform_driver_register(&aat2870_regulator_driver);189}190subsys_initcall(aat2870_regulator_init);191 192static void __exit aat2870_regulator_exit(void)193{194 platform_driver_unregister(&aat2870_regulator_driver);195}196module_exit(aat2870_regulator_exit);197 198MODULE_DESCRIPTION("AnalogicTech AAT2870 Regulator");199MODULE_LICENSE("GPL");200MODULE_AUTHOR("Jin Park <jinyoungp@nvidia.com>");201MODULE_ALIAS("platform:aat2870-regulator");202