1134458Siedowse// SPDX-License-Identifier: GPL-2.0-only 2134458Siedowse/* 3134458Siedowse * linux/drivers/regulator/aat2870-regulator.c 4134458Siedowse * 5134458Siedowse * Copyright (c) 2011, NVIDIA Corporation. 6134458Siedowse * Author: Jin Park <jinyoungp@nvidia.com> 7134458Siedowse */ 8134458Siedowse 9134458Siedowse#include <linux/kernel.h> 10134458Siedowse#include <linux/init.h> 11134458Siedowse#include <linux/err.h> 12134458Siedowse#include <linux/module.h> 13134458Siedowse#include <linux/slab.h> 14134458Siedowse#include <linux/platform_device.h> 15134458Siedowse#include <linux/regulator/driver.h> 16134458Siedowse#include <linux/regulator/machine.h> 17134458Siedowse#include <linux/mfd/aat2870.h> 18134458Siedowse 19134458Siedowsestruct aat2870_regulator { 20134458Siedowse struct aat2870_data *aat2870; 21134458Siedowse struct regulator_desc desc; 22134458Siedowse 23134458Siedowse u8 enable_addr; 24134458Siedowse u8 enable_shift; 25134458Siedowse u8 enable_mask; 26134458Siedowse 27134458Siedowse u8 voltage_addr; 28134458Siedowse u8 voltage_shift; 29134458Siedowse u8 voltage_mask; 30134458Siedowse}; 31134458Siedowse 32134458Siedowsestatic int aat2870_ldo_set_voltage_sel(struct regulator_dev *rdev, 33134458Siedowse unsigned selector) 34134458Siedowse{ 35134458Siedowse struct aat2870_regulator *ri = rdev_get_drvdata(rdev); 36134458Siedowse struct aat2870_data *aat2870 = ri->aat2870; 37134458Siedowse 38134458Siedowse return aat2870->update(aat2870, ri->voltage_addr, ri->voltage_mask, 39134458Siedowse selector << ri->voltage_shift); 40134458Siedowse} 41134458Siedowse 42134458Siedowsestatic int aat2870_ldo_get_voltage_sel(struct regulator_dev *rdev) 43134458Siedowse{ 44134458Siedowse struct aat2870_regulator *ri = rdev_get_drvdata(rdev); 45134458Siedowse struct aat2870_data *aat2870 = ri->aat2870; 46134458Siedowse u8 val; 47134458Siedowse int ret; 48134458Siedowse 49134458Siedowse ret = aat2870->read(aat2870, ri->voltage_addr, &val); 50134458Siedowse if (ret) 51134458Siedowse return ret; 52134458Siedowse 53134458Siedowse return (val & ri->voltage_mask) >> ri->voltage_shift; 54134458Siedowse} 55134458Siedowse 56134458Siedowsestatic int aat2870_ldo_enable(struct regulator_dev *rdev) 57153504Smarcel{ 58134458Siedowse struct aat2870_regulator *ri = rdev_get_drvdata(rdev); 59134458Siedowse struct aat2870_data *aat2870 = ri->aat2870; 60134458Siedowse 61134458Siedowse return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask, 62134458Siedowse ri->enable_mask); 63134458Siedowse} 64134458Siedowse 65134458Siedowsestatic int aat2870_ldo_disable(struct regulator_dev *rdev) 66134458Siedowse{ 67134458Siedowse struct aat2870_regulator *ri = rdev_get_drvdata(rdev); 68134458Siedowse struct aat2870_data *aat2870 = ri->aat2870; 69134458Siedowse 70134458Siedowse return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask, 0); 71134458Siedowse} 72134458Siedowse 73134458Siedowsestatic int aat2870_ldo_is_enabled(struct regulator_dev *rdev) 74134458Siedowse{ 75134458Siedowse struct aat2870_regulator *ri = rdev_get_drvdata(rdev); 76134458Siedowse struct aat2870_data *aat2870 = ri->aat2870; 77134458Siedowse u8 val; 78134458Siedowse int ret; 79134458Siedowse 80134458Siedowse ret = aat2870->read(aat2870, ri->enable_addr, &val); 81223695Sdfr if (ret) 82134458Siedowse return ret; 83134458Siedowse 84153504Smarcel return val & ri->enable_mask ? 1 : 0; 85134458Siedowse} 86134458Siedowse 87134458Siedowsestatic const struct regulator_ops aat2870_ldo_ops = { 88134458Siedowse .list_voltage = regulator_list_voltage_table, 89134458Siedowse .map_voltage = regulator_map_voltage_ascend, 90134458Siedowse .set_voltage_sel = aat2870_ldo_set_voltage_sel, 91134458Siedowse .get_voltage_sel = aat2870_ldo_get_voltage_sel, 92134458Siedowse .enable = aat2870_ldo_enable, 93134458Siedowse .disable = aat2870_ldo_disable, 94134458Siedowse .is_enabled = aat2870_ldo_is_enabled, 95134458Siedowse}; 96134458Siedowse 97134458Siedowsestatic const unsigned int aat2870_ldo_voltages[] = { 98134458Siedowse 1200000, 1300000, 1500000, 1600000, 99134458Siedowse 1800000, 2000000, 2200000, 2500000, 100134458Siedowse 2600000, 2700000, 2800000, 2900000, 101134458Siedowse 3000000, 3100000, 3200000, 3300000, 102134458Siedowse}; 103134458Siedowse 104134458Siedowse#define AAT2870_LDO(ids) \ 105134458Siedowse { \ 106134458Siedowse .desc = { \ 107134458Siedowse .name = #ids, \ 108134458Siedowse .id = AAT2870_ID_##ids, \ 109134458Siedowse .n_voltages = ARRAY_SIZE(aat2870_ldo_voltages), \ 110134458Siedowse .volt_table = aat2870_ldo_voltages, \ 111134458Siedowse .ops = &aat2870_ldo_ops, \ 112134458Siedowse .type = REGULATOR_VOLTAGE, \ 113134458Siedowse .owner = THIS_MODULE, \ 114134458Siedowse }, \ 115134458Siedowse } 116134458Siedowse 117134458Siedowsestatic struct aat2870_regulator aat2870_regulators[] = { 118134458Siedowse AAT2870_LDO(LDOA), 119134458Siedowse AAT2870_LDO(LDOB), 120134458Siedowse AAT2870_LDO(LDOC), 121134458Siedowse AAT2870_LDO(LDOD), 122134458Siedowse}; 123134458Siedowse 124134458Siedowsestatic struct aat2870_regulator *aat2870_get_regulator(int id) 125134458Siedowse{ 126134458Siedowse struct aat2870_regulator *ri = NULL; 127134458Siedowse int i; 128134458Siedowse 129134458Siedowse for (i = 0; i < ARRAY_SIZE(aat2870_regulators); i++) { 130134458Siedowse ri = &aat2870_regulators[i]; 131134458Siedowse if (ri->desc.id == id) 132134458Siedowse break; 133134458Siedowse } 134134458Siedowse 135134458Siedowse if (i == ARRAY_SIZE(aat2870_regulators)) 136134458Siedowse return NULL; 137134458Siedowse 138134458Siedowse ri->enable_addr = AAT2870_LDO_EN; 139134458Siedowse ri->enable_shift = id - AAT2870_ID_LDOA; 140134458Siedowse ri->enable_mask = 0x1 << ri->enable_shift; 141153504Smarcel 142134458Siedowse ri->voltage_addr = (id - AAT2870_ID_LDOA) / 2 ? 143134458Siedowse AAT2870_LDO_CD : AAT2870_LDO_AB; 144134458Siedowse ri->voltage_shift = (id - AAT2870_ID_LDOA) % 2 ? 0 : 4; 145134458Siedowse ri->voltage_mask = 0xF << ri->voltage_shift; 146134458Siedowse 147134458Siedowse return ri; 148134458Siedowse} 149134458Siedowse 150134458Siedowsestatic int aat2870_regulator_probe(struct platform_device *pdev) 151134458Siedowse{ 152134458Siedowse struct aat2870_regulator *ri; 153134458Siedowse struct regulator_config config = { }; 154134458Siedowse struct regulator_dev *rdev; 155134458Siedowse 156134458Siedowse ri = aat2870_get_regulator(pdev->id); 157134458Siedowse if (!ri) { 158134458Siedowse dev_err(&pdev->dev, "Invalid device ID, %d\n", pdev->id); 159134458Siedowse return -EINVAL; 160134458Siedowse } 161134458Siedowse ri->aat2870 = dev_get_drvdata(pdev->dev.parent); 162134458Siedowse 163134458Siedowse config.dev = &pdev->dev; 164134458Siedowse config.driver_data = ri; 165134458Siedowse config.init_data = dev_get_platdata(&pdev->dev); 166134458Siedowse 167134458Siedowse rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config); 168134458Siedowse if (IS_ERR(rdev)) { 169134458Siedowse dev_err(&pdev->dev, "Failed to register regulator %s\n", 170134458Siedowse ri->desc.name); 171134458Siedowse return PTR_ERR(rdev); 172134458Siedowse } 173134458Siedowse platform_set_drvdata(pdev, rdev); 174134458Siedowse 175134458Siedowse return 0; 176134458Siedowse} 177134458Siedowse 178134458Siedowsestatic struct platform_driver aat2870_regulator_driver = { 179134458Siedowse .driver = { 180134458Siedowse .name = "aat2870-regulator", 181134458Siedowse .probe_type = PROBE_PREFER_ASYNCHRONOUS, 182134458Siedowse }, 183134458Siedowse .probe = aat2870_regulator_probe, 184134458Siedowse}; 185134458Siedowse 186134458Siedowsestatic int __init aat2870_regulator_init(void) 187134458Siedowse{ 188134458Siedowse return platform_driver_register(&aat2870_regulator_driver); 189134458Siedowse} 190134458Siedowsesubsys_initcall(aat2870_regulator_init); 191134458Siedowse 192134458Siedowsestatic void __exit aat2870_regulator_exit(void) 193134458Siedowse{ 194134458Siedowse platform_driver_unregister(&aat2870_regulator_driver); 195134458Siedowse} 196241036Sandreastmodule_exit(aat2870_regulator_exit); 197241036Sandreast 198241036SandreastMODULE_DESCRIPTION("AnalogicTech AAT2870 Regulator"); 199241036SandreastMODULE_LICENSE("GPL"); 200241036SandreastMODULE_AUTHOR("Jin Park <jinyoungp@nvidia.com>"); 201241036SandreastMODULE_ALIAS("platform:aat2870-regulator"); 202241036Sandreast