1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/ 4 * Tero Kristo <t-kristo@ti.com> 5 */ 6 7#include <common.h> 8#include <dm.h> 9#include <i2c.h> 10#include <dm/device_compat.h> 11#include <power/regulator.h> 12 13#define TPS62360_REG_SET0 0 14 15#define TPS62360_I2C_CHIP 0x60 16 17#define TPS62360_VSEL_STEPSIZE 10000 /* In uV */ 18 19struct tps62360_regulator_config { 20 u32 vmin; 21 u32 vmax; 22}; 23 24struct tps62360_regulator_pdata { 25 u8 vsel_offset; 26 struct udevice *i2c; 27 struct tps62360_regulator_config *config; 28}; 29 30/* 31 * TPS62362/TPS62363 are just re-using these values for now, their preset 32 * voltage values are just different compared to TPS62360/TPS62361. 33 */ 34static struct tps62360_regulator_config tps62360_data = { 35 .vmin = 770000, 36 .vmax = 1400000, 37}; 38 39static struct tps62360_regulator_config tps62361_data = { 40 .vmin = 500000, 41 .vmax = 1770000, 42}; 43 44static int tps62360_regulator_set_value(struct udevice *dev, int uV) 45{ 46 struct tps62360_regulator_pdata *pdata = dev_get_plat(dev); 47 u8 regval; 48 49 if (uV < pdata->config->vmin || uV > pdata->config->vmax) 50 return -EINVAL; 51 52 uV -= pdata->config->vmin; 53 54 uV = DIV_ROUND_UP(uV, TPS62360_VSEL_STEPSIZE); 55 56 if (uV > U8_MAX) 57 return -EINVAL; 58 59 regval = (u8)uV; 60 61 return dm_i2c_write(pdata->i2c, TPS62360_REG_SET0 + pdata->vsel_offset, 62 ®val, 1); 63} 64 65static int tps62360_regulator_get_value(struct udevice *dev) 66{ 67 u8 regval; 68 int ret; 69 struct tps62360_regulator_pdata *pdata = dev_get_plat(dev); 70 71 ret = dm_i2c_read(pdata->i2c, TPS62360_REG_SET0 + pdata->vsel_offset, 72 ®val, 1); 73 if (ret) { 74 dev_err(dev, "i2c read failed: %d\n", ret); 75 return ret; 76 } 77 78 return (u32)regval * TPS62360_VSEL_STEPSIZE + pdata->config->vmin; 79} 80 81static int tps62360_regulator_probe(struct udevice *dev) 82{ 83 struct tps62360_regulator_pdata *pdata = dev_get_plat(dev); 84 u8 vsel0; 85 u8 vsel1; 86 int ret; 87 88 pdata->config = (void *)dev_get_driver_data(dev); 89 90 vsel0 = dev_read_bool(dev, "ti,vsel0-state-high"); 91 vsel1 = dev_read_bool(dev, "ti,vsel1-state-high"); 92 93 pdata->vsel_offset = vsel0 + vsel1 * 2; 94 95 ret = i2c_get_chip(dev->parent, TPS62360_I2C_CHIP, 1, &pdata->i2c); 96 if (ret) { 97 dev_err(dev, "i2c dev get failed.\n"); 98 return ret; 99 } 100 101 return 0; 102} 103 104static const struct dm_regulator_ops tps62360_regulator_ops = { 105 .get_value = tps62360_regulator_get_value, 106 .set_value = tps62360_regulator_set_value, 107}; 108 109static const struct udevice_id tps62360_regulator_ids[] = { 110 { .compatible = "ti,tps62360", .data = (ulong)&tps62360_data }, 111 { .compatible = "ti,tps62361", .data = (ulong)&tps62361_data }, 112 { .compatible = "ti,tps62362", .data = (ulong)&tps62360_data }, 113 { .compatible = "ti,tps62363", .data = (ulong)&tps62361_data }, 114 { }, 115}; 116 117U_BOOT_DRIVER(tps62360_regulator) = { 118 .name = "tps62360_regulator", 119 .id = UCLASS_REGULATOR, 120 .ops = &tps62360_regulator_ops, 121 .of_match = tps62360_regulator_ids, 122 .plat_auto = sizeof(struct tps62360_regulator_pdata), 123 .probe = tps62360_regulator_probe, 124}; 125