1 /* 2 * pbias-regulator.c 3 * 4 * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ 5 * Author: Balaji T K <balajitk@ti.com> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation version 2. 10 * 11 * This program is distributed "as is" WITHOUT ANY WARRANTY of any 12 * kind, whether express or implied; without even the implied warranty 13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 */ 16 17 #include <linux/err.h> 18 #include <linux/io.h> 19 #include <linux/module.h> 20 #include <linux/mfd/syscon.h> 21 #include <linux/platform_device.h> 22 #include <linux/regulator/driver.h> 23 #include <linux/regulator/machine.h> 24 #include <linux/regulator/of_regulator.h> 25 #include <linux/regmap.h> 26 #include <linux/slab.h> 27 #include <linux/of.h> 28 #include <linux/of_device.h> 29 30 struct pbias_reg_info { 31 u32 enable; 32 u32 enable_mask; 33 u32 vmode; 34 unsigned int enable_time; 35 char *name; 36 }; 37 38 struct pbias_regulator_data { 39 struct regulator_desc desc; 40 void __iomem *pbias_addr; 41 unsigned int pbias_reg; 42 struct regulator_dev *dev; 43 struct regmap *syscon; 44 const struct pbias_reg_info *info; 45 int voltage; 46 }; 47 48 static int pbias_regulator_set_voltage(struct regulator_dev *dev, 49 int min_uV, int max_uV, unsigned *selector) 50 { 51 struct pbias_regulator_data *data = rdev_get_drvdata(dev); 52 const struct pbias_reg_info *info = data->info; 53 int ret, vmode; 54 55 if (min_uV <= 1800000) 56 vmode = 0; 57 else if (min_uV > 1800000) 58 vmode = info->vmode; 59 60 ret = regmap_update_bits(data->syscon, data->pbias_reg, 61 info->vmode, vmode); 62 63 return ret; 64 } 65 66 static int pbias_regulator_get_voltage(struct regulator_dev *rdev) 67 { 68 struct pbias_regulator_data *data = rdev_get_drvdata(rdev); 69 const struct pbias_reg_info *info = data->info; 70 int value, voltage; 71 72 regmap_read(data->syscon, data->pbias_reg, &value); 73 value &= info->vmode; 74 75 voltage = value ? 3000000 : 1800000; 76 77 return voltage; 78 } 79 80 static int pbias_regulator_enable(struct regulator_dev *rdev) 81 { 82 struct pbias_regulator_data *data = rdev_get_drvdata(rdev); 83 const struct pbias_reg_info *info = data->info; 84 int ret; 85 86 ret = regmap_update_bits(data->syscon, data->pbias_reg, 87 info->enable_mask, info->enable); 88 89 return ret; 90 } 91 92 static int pbias_regulator_disable(struct regulator_dev *rdev) 93 { 94 struct pbias_regulator_data *data = rdev_get_drvdata(rdev); 95 const struct pbias_reg_info *info = data->info; 96 int ret; 97 98 ret = regmap_update_bits(data->syscon, data->pbias_reg, 99 info->enable_mask, 0); 100 return ret; 101 } 102 103 static int pbias_regulator_is_enable(struct regulator_dev *rdev) 104 { 105 struct pbias_regulator_data *data = rdev_get_drvdata(rdev); 106 const struct pbias_reg_info *info = data->info; 107 int value; 108 109 regmap_read(data->syscon, data->pbias_reg, &value); 110 111 return (value & info->enable_mask) == info->enable_mask; 112 } 113 114 static struct regulator_ops pbias_regulator_voltage_ops = { 115 .set_voltage = pbias_regulator_set_voltage, 116 .get_voltage = pbias_regulator_get_voltage, 117 .enable = pbias_regulator_enable, 118 .disable = pbias_regulator_disable, 119 .is_enabled = pbias_regulator_is_enable, 120 }; 121 122 static const struct pbias_reg_info pbias_mmc_omap2430 = { 123 .enable = BIT(1), 124 .enable_mask = BIT(1), 125 .vmode = BIT(0), 126 .enable_time = 100, 127 .name = "pbias_mmc_omap2430" 128 }; 129 130 static const struct pbias_reg_info pbias_sim_omap3 = { 131 .enable = BIT(9), 132 .enable_mask = BIT(9), 133 .vmode = BIT(8), 134 .enable_time = 100, 135 .name = "pbias_sim_omap3" 136 }; 137 138 static const struct pbias_reg_info pbias_mmc_omap4 = { 139 .enable = BIT(26) | BIT(22), 140 .enable_mask = BIT(26) | BIT(25) | BIT(22), 141 .vmode = BIT(21), 142 .enable_time = 100, 143 .name = "pbias_mmc_omap4" 144 }; 145 146 static const struct pbias_reg_info pbias_mmc_omap5 = { 147 .enable = BIT(27) | BIT(26), 148 .enable_mask = BIT(27) | BIT(25) | BIT(26), 149 .vmode = BIT(21), 150 .enable_time = 100, 151 .name = "pbias_mmc_omap5" 152 }; 153 154 static struct of_regulator_match pbias_matches[] = { 155 { .name = "pbias_mmc_omap2430", .driver_data = (void *)&pbias_mmc_omap2430}, 156 { .name = "pbias_sim_omap3", .driver_data = (void *)&pbias_sim_omap3}, 157 { .name = "pbias_mmc_omap4", .driver_data = (void *)&pbias_mmc_omap4}, 158 { .name = "pbias_mmc_omap5", .driver_data = (void *)&pbias_mmc_omap5}, 159 }; 160 #define PBIAS_NUM_REGS ARRAY_SIZE(pbias_matches) 161 162 static const struct of_device_id pbias_of_match[] = { 163 { .compatible = "ti,pbias-omap", }, 164 {}, 165 }; 166 MODULE_DEVICE_TABLE(of, pbias_of_match); 167 168 static int pbias_regulator_probe(struct platform_device *pdev) 169 { 170 struct device_node *np = pdev->dev.of_node; 171 struct pbias_regulator_data *drvdata; 172 struct resource *res; 173 struct regulator_config cfg = { }; 174 struct regmap *syscon; 175 const struct pbias_reg_info *info; 176 int ret = 0; 177 int count, idx, data_idx = 0; 178 179 count = of_regulator_match(&pdev->dev, np, pbias_matches, 180 PBIAS_NUM_REGS); 181 if (count < 0) 182 return count; 183 184 drvdata = devm_kzalloc(&pdev->dev, sizeof(struct pbias_regulator_data) 185 * count, GFP_KERNEL); 186 if (drvdata == NULL) { 187 dev_err(&pdev->dev, "Failed to allocate device data\n"); 188 return -ENOMEM; 189 } 190 191 syscon = syscon_regmap_lookup_by_phandle(np, "syscon"); 192 if (IS_ERR(syscon)) 193 return PTR_ERR(syscon); 194 195 cfg.dev = &pdev->dev; 196 197 for (idx = 0; idx < PBIAS_NUM_REGS && data_idx < count; idx++) { 198 if (!pbias_matches[idx].init_data || 199 !pbias_matches[idx].of_node) 200 continue; 201 202 info = pbias_matches[idx].driver_data; 203 if (!info) 204 return -ENODEV; 205 206 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 207 if (!res) 208 return -EINVAL; 209 210 drvdata[data_idx].pbias_reg = res->start; 211 drvdata[data_idx].syscon = syscon; 212 drvdata[data_idx].info = info; 213 drvdata[data_idx].desc.name = info->name; 214 drvdata[data_idx].desc.owner = THIS_MODULE; 215 drvdata[data_idx].desc.type = REGULATOR_VOLTAGE; 216 drvdata[data_idx].desc.ops = &pbias_regulator_voltage_ops; 217 drvdata[data_idx].desc.n_voltages = 2; 218 drvdata[data_idx].desc.enable_time = info->enable_time; 219 220 cfg.init_data = pbias_matches[idx].init_data; 221 cfg.driver_data = &drvdata[data_idx]; 222 cfg.of_node = pbias_matches[idx].of_node; 223 224 drvdata[data_idx].dev = devm_regulator_register(&pdev->dev, 225 &drvdata[data_idx].desc, &cfg); 226 if (IS_ERR(drvdata[data_idx].dev)) { 227 ret = PTR_ERR(drvdata[data_idx].dev); 228 dev_err(&pdev->dev, 229 "Failed to register regulator: %d\n", ret); 230 goto err_regulator; 231 } 232 data_idx++; 233 } 234 235 platform_set_drvdata(pdev, drvdata); 236 237 err_regulator: 238 return ret; 239 } 240 241 static struct platform_driver pbias_regulator_driver = { 242 .probe = pbias_regulator_probe, 243 .driver = { 244 .name = "pbias-regulator", 245 .owner = THIS_MODULE, 246 .of_match_table = of_match_ptr(pbias_of_match), 247 }, 248 }; 249 250 module_platform_driver(pbias_regulator_driver); 251 252 MODULE_AUTHOR("Balaji T K <balajitk@ti.com>"); 253 MODULE_DESCRIPTION("pbias voltage regulator"); 254 MODULE_LICENSE("GPL"); 255 MODULE_ALIAS("platform:pbias-regulator"); 256