111469e0bSBalaji T K /* 211469e0bSBalaji T K * pbias-regulator.c 311469e0bSBalaji T K * 411469e0bSBalaji T K * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ 511469e0bSBalaji T K * Author: Balaji T K <balajitk@ti.com> 611469e0bSBalaji T K * 711469e0bSBalaji T K * This program is free software; you can redistribute it and/or 811469e0bSBalaji T K * modify it under the terms of the GNU General Public License as 911469e0bSBalaji T K * published by the Free Software Foundation version 2. 1011469e0bSBalaji T K * 1111469e0bSBalaji T K * This program is distributed "as is" WITHOUT ANY WARRANTY of any 1211469e0bSBalaji T K * kind, whether express or implied; without even the implied warranty 1311469e0bSBalaji T K * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1411469e0bSBalaji T K * GNU General Public License for more details. 1511469e0bSBalaji T K */ 1611469e0bSBalaji T K 1711469e0bSBalaji T K #include <linux/err.h> 1811469e0bSBalaji T K #include <linux/io.h> 1911469e0bSBalaji T K #include <linux/module.h> 2011469e0bSBalaji T K #include <linux/mfd/syscon.h> 2111469e0bSBalaji T K #include <linux/platform_device.h> 2211469e0bSBalaji T K #include <linux/regulator/driver.h> 2311469e0bSBalaji T K #include <linux/regulator/machine.h> 2411469e0bSBalaji T K #include <linux/regulator/of_regulator.h> 2511469e0bSBalaji T K #include <linux/regmap.h> 2611469e0bSBalaji T K #include <linux/slab.h> 2711469e0bSBalaji T K #include <linux/of.h> 2811469e0bSBalaji T K #include <linux/of_device.h> 2911469e0bSBalaji T K 3011469e0bSBalaji T K struct pbias_reg_info { 3111469e0bSBalaji T K u32 enable; 3211469e0bSBalaji T K u32 enable_mask; 3311469e0bSBalaji T K u32 vmode; 3411469e0bSBalaji T K unsigned int enable_time; 3511469e0bSBalaji T K char *name; 3611469e0bSBalaji T K }; 3711469e0bSBalaji T K 3811469e0bSBalaji T K struct pbias_regulator_data { 3911469e0bSBalaji T K struct regulator_desc desc; 4011469e0bSBalaji T K void __iomem *pbias_addr; 4111469e0bSBalaji T K unsigned int pbias_reg; 4211469e0bSBalaji T K struct regulator_dev *dev; 4311469e0bSBalaji T K struct regmap *syscon; 4411469e0bSBalaji T K const struct pbias_reg_info *info; 4511469e0bSBalaji T K int voltage; 4611469e0bSBalaji T K }; 4711469e0bSBalaji T K 4811469e0bSBalaji T K static int pbias_regulator_set_voltage(struct regulator_dev *dev, 4911469e0bSBalaji T K int min_uV, int max_uV, unsigned *selector) 5011469e0bSBalaji T K { 5111469e0bSBalaji T K struct pbias_regulator_data *data = rdev_get_drvdata(dev); 5211469e0bSBalaji T K const struct pbias_reg_info *info = data->info; 5311469e0bSBalaji T K int ret, vmode; 5411469e0bSBalaji T K 5511469e0bSBalaji T K if (min_uV <= 1800000) 5611469e0bSBalaji T K vmode = 0; 5711469e0bSBalaji T K else if (min_uV > 1800000) 5811469e0bSBalaji T K vmode = info->vmode; 5911469e0bSBalaji T K 6011469e0bSBalaji T K ret = regmap_update_bits(data->syscon, data->pbias_reg, 6111469e0bSBalaji T K info->vmode, vmode); 6211469e0bSBalaji T K 6311469e0bSBalaji T K return ret; 6411469e0bSBalaji T K } 6511469e0bSBalaji T K 6611469e0bSBalaji T K static int pbias_regulator_get_voltage(struct regulator_dev *rdev) 6711469e0bSBalaji T K { 6811469e0bSBalaji T K struct pbias_regulator_data *data = rdev_get_drvdata(rdev); 6911469e0bSBalaji T K const struct pbias_reg_info *info = data->info; 7011469e0bSBalaji T K int value, voltage; 7111469e0bSBalaji T K 7211469e0bSBalaji T K regmap_read(data->syscon, data->pbias_reg, &value); 7311469e0bSBalaji T K value &= info->vmode; 7411469e0bSBalaji T K 7511469e0bSBalaji T K voltage = value ? 3000000 : 1800000; 7611469e0bSBalaji T K 7711469e0bSBalaji T K return voltage; 7811469e0bSBalaji T K } 7911469e0bSBalaji T K 8011469e0bSBalaji T K static int pbias_regulator_enable(struct regulator_dev *rdev) 8111469e0bSBalaji T K { 8211469e0bSBalaji T K struct pbias_regulator_data *data = rdev_get_drvdata(rdev); 8311469e0bSBalaji T K const struct pbias_reg_info *info = data->info; 8411469e0bSBalaji T K int ret; 8511469e0bSBalaji T K 8611469e0bSBalaji T K ret = regmap_update_bits(data->syscon, data->pbias_reg, 8711469e0bSBalaji T K info->enable_mask, info->enable); 8811469e0bSBalaji T K 8911469e0bSBalaji T K return ret; 9011469e0bSBalaji T K } 9111469e0bSBalaji T K 9211469e0bSBalaji T K static int pbias_regulator_disable(struct regulator_dev *rdev) 9311469e0bSBalaji T K { 9411469e0bSBalaji T K struct pbias_regulator_data *data = rdev_get_drvdata(rdev); 9511469e0bSBalaji T K const struct pbias_reg_info *info = data->info; 9611469e0bSBalaji T K int ret; 9711469e0bSBalaji T K 9811469e0bSBalaji T K ret = regmap_update_bits(data->syscon, data->pbias_reg, 9911469e0bSBalaji T K info->enable_mask, 0); 10011469e0bSBalaji T K return ret; 10111469e0bSBalaji T K } 10211469e0bSBalaji T K 10311469e0bSBalaji T K static int pbias_regulator_is_enable(struct regulator_dev *rdev) 10411469e0bSBalaji T K { 10511469e0bSBalaji T K struct pbias_regulator_data *data = rdev_get_drvdata(rdev); 10611469e0bSBalaji T K const struct pbias_reg_info *info = data->info; 10711469e0bSBalaji T K int value; 10811469e0bSBalaji T K 10911469e0bSBalaji T K regmap_read(data->syscon, data->pbias_reg, &value); 11011469e0bSBalaji T K 11111469e0bSBalaji T K return (value & info->enable_mask) == info->enable_mask; 11211469e0bSBalaji T K } 11311469e0bSBalaji T K 11411469e0bSBalaji T K static struct regulator_ops pbias_regulator_voltage_ops = { 11511469e0bSBalaji T K .set_voltage = pbias_regulator_set_voltage, 11611469e0bSBalaji T K .get_voltage = pbias_regulator_get_voltage, 11711469e0bSBalaji T K .enable = pbias_regulator_enable, 11811469e0bSBalaji T K .disable = pbias_regulator_disable, 11911469e0bSBalaji T K .is_enabled = pbias_regulator_is_enable, 12011469e0bSBalaji T K }; 12111469e0bSBalaji T K 12211469e0bSBalaji T K static const struct pbias_reg_info pbias_mmc_omap2430 = { 12311469e0bSBalaji T K .enable = BIT(1), 12411469e0bSBalaji T K .enable_mask = BIT(1), 12511469e0bSBalaji T K .vmode = BIT(0), 12611469e0bSBalaji T K .enable_time = 100, 12711469e0bSBalaji T K .name = "pbias_mmc_omap2430" 12811469e0bSBalaji T K }; 12911469e0bSBalaji T K 13011469e0bSBalaji T K static const struct pbias_reg_info pbias_sim_omap3 = { 13111469e0bSBalaji T K .enable = BIT(9), 13211469e0bSBalaji T K .enable_mask = BIT(9), 13311469e0bSBalaji T K .vmode = BIT(8), 13411469e0bSBalaji T K .enable_time = 100, 13511469e0bSBalaji T K .name = "pbias_sim_omap3" 13611469e0bSBalaji T K }; 13711469e0bSBalaji T K 13811469e0bSBalaji T K static const struct pbias_reg_info pbias_mmc_omap4 = { 13911469e0bSBalaji T K .enable = BIT(26) | BIT(22), 14011469e0bSBalaji T K .enable_mask = BIT(26) | BIT(25) | BIT(22), 14111469e0bSBalaji T K .vmode = BIT(21), 14211469e0bSBalaji T K .enable_time = 100, 14311469e0bSBalaji T K .name = "pbias_mmc_omap4" 14411469e0bSBalaji T K }; 14511469e0bSBalaji T K 14611469e0bSBalaji T K static const struct pbias_reg_info pbias_mmc_omap5 = { 14711469e0bSBalaji T K .enable = BIT(27) | BIT(26), 14811469e0bSBalaji T K .enable_mask = BIT(27) | BIT(25) | BIT(26), 14911469e0bSBalaji T K .vmode = BIT(21), 15011469e0bSBalaji T K .enable_time = 100, 15111469e0bSBalaji T K .name = "pbias_mmc_omap5" 15211469e0bSBalaji T K }; 15311469e0bSBalaji T K 15411469e0bSBalaji T K static struct of_regulator_match pbias_matches[] = { 15511469e0bSBalaji T K { .name = "pbias_mmc_omap2430", .driver_data = (void *)&pbias_mmc_omap2430}, 15611469e0bSBalaji T K { .name = "pbias_sim_omap3", .driver_data = (void *)&pbias_sim_omap3}, 15711469e0bSBalaji T K { .name = "pbias_mmc_omap4", .driver_data = (void *)&pbias_mmc_omap4}, 15811469e0bSBalaji T K { .name = "pbias_mmc_omap5", .driver_data = (void *)&pbias_mmc_omap5}, 15911469e0bSBalaji T K }; 16011469e0bSBalaji T K #define PBIAS_NUM_REGS ARRAY_SIZE(pbias_matches) 16111469e0bSBalaji T K 16211469e0bSBalaji T K static const struct of_device_id pbias_of_match[] = { 16311469e0bSBalaji T K { .compatible = "ti,pbias-omap", }, 16411469e0bSBalaji T K {}, 16511469e0bSBalaji T K }; 16611469e0bSBalaji T K MODULE_DEVICE_TABLE(of, pbias_of_match); 16711469e0bSBalaji T K 16811469e0bSBalaji T K static int pbias_regulator_probe(struct platform_device *pdev) 16911469e0bSBalaji T K { 17011469e0bSBalaji T K struct device_node *np = pdev->dev.of_node; 17111469e0bSBalaji T K struct pbias_regulator_data *drvdata; 17211469e0bSBalaji T K struct resource *res; 17311469e0bSBalaji T K struct regulator_config cfg = { }; 17411469e0bSBalaji T K struct regmap *syscon; 17511469e0bSBalaji T K const struct pbias_reg_info *info; 17611469e0bSBalaji T K int ret = 0; 17711469e0bSBalaji T K int count, idx, data_idx = 0; 17811469e0bSBalaji T K 17911469e0bSBalaji T K count = of_regulator_match(&pdev->dev, np, pbias_matches, 18011469e0bSBalaji T K PBIAS_NUM_REGS); 18111469e0bSBalaji T K if (count < 0) 18211469e0bSBalaji T K return count; 18311469e0bSBalaji T K 18411469e0bSBalaji T K drvdata = devm_kzalloc(&pdev->dev, sizeof(struct pbias_regulator_data) 18511469e0bSBalaji T K * count, GFP_KERNEL); 18611469e0bSBalaji T K if (drvdata == NULL) { 18711469e0bSBalaji T K dev_err(&pdev->dev, "Failed to allocate device data\n"); 18811469e0bSBalaji T K return -ENOMEM; 18911469e0bSBalaji T K } 19011469e0bSBalaji T K 19111469e0bSBalaji T K syscon = syscon_regmap_lookup_by_phandle(np, "syscon"); 19211469e0bSBalaji T K if (IS_ERR(syscon)) 19311469e0bSBalaji T K return PTR_ERR(syscon); 19411469e0bSBalaji T K 19511469e0bSBalaji T K cfg.dev = &pdev->dev; 19611469e0bSBalaji T K 19711469e0bSBalaji T K for (idx = 0; idx < PBIAS_NUM_REGS && data_idx < count; idx++) { 19811469e0bSBalaji T K if (!pbias_matches[idx].init_data || 19911469e0bSBalaji T K !pbias_matches[idx].of_node) 20011469e0bSBalaji T K continue; 20111469e0bSBalaji T K 20211469e0bSBalaji T K info = pbias_matches[idx].driver_data; 20311469e0bSBalaji T K if (!info) 20411469e0bSBalaji T K return -ENODEV; 20511469e0bSBalaji T K 20611469e0bSBalaji T K res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 20711469e0bSBalaji T K if (!res) 20811469e0bSBalaji T K return -EINVAL; 20911469e0bSBalaji T K 21011469e0bSBalaji T K drvdata[data_idx].pbias_reg = res->start; 21111469e0bSBalaji T K drvdata[data_idx].syscon = syscon; 21211469e0bSBalaji T K drvdata[data_idx].info = info; 21311469e0bSBalaji T K drvdata[data_idx].desc.name = info->name; 21411469e0bSBalaji T K drvdata[data_idx].desc.owner = THIS_MODULE; 21511469e0bSBalaji T K drvdata[data_idx].desc.type = REGULATOR_VOLTAGE; 21611469e0bSBalaji T K drvdata[data_idx].desc.ops = &pbias_regulator_voltage_ops; 21711469e0bSBalaji T K drvdata[data_idx].desc.n_voltages = 2; 21811469e0bSBalaji T K drvdata[data_idx].desc.enable_time = info->enable_time; 21911469e0bSBalaji T K 22011469e0bSBalaji T K cfg.init_data = pbias_matches[idx].init_data; 22111469e0bSBalaji T K cfg.driver_data = &drvdata[data_idx]; 22211469e0bSBalaji T K cfg.of_node = pbias_matches[idx].of_node; 22311469e0bSBalaji T K 22411469e0bSBalaji T K drvdata[data_idx].dev = devm_regulator_register(&pdev->dev, 22511469e0bSBalaji T K &drvdata[data_idx].desc, &cfg); 22611469e0bSBalaji T K if (IS_ERR(drvdata[data_idx].dev)) { 22711469e0bSBalaji T K ret = PTR_ERR(drvdata[data_idx].dev); 22811469e0bSBalaji T K dev_err(&pdev->dev, 22911469e0bSBalaji T K "Failed to register regulator: %d\n", ret); 23011469e0bSBalaji T K goto err_regulator; 23111469e0bSBalaji T K } 23211469e0bSBalaji T K data_idx++; 23311469e0bSBalaji T K } 23411469e0bSBalaji T K 23511469e0bSBalaji T K platform_set_drvdata(pdev, drvdata); 23611469e0bSBalaji T K 23711469e0bSBalaji T K err_regulator: 23811469e0bSBalaji T K return ret; 23911469e0bSBalaji T K } 24011469e0bSBalaji T K 24111469e0bSBalaji T K static struct platform_driver pbias_regulator_driver = { 24211469e0bSBalaji T K .probe = pbias_regulator_probe, 24311469e0bSBalaji T K .driver = { 24411469e0bSBalaji T K .name = "pbias-regulator", 24511469e0bSBalaji T K .owner = THIS_MODULE, 24611469e0bSBalaji T K .of_match_table = of_match_ptr(pbias_of_match), 24711469e0bSBalaji T K }, 24811469e0bSBalaji T K }; 24911469e0bSBalaji T K 25011469e0bSBalaji T K module_platform_driver(pbias_regulator_driver); 25111469e0bSBalaji T K 25211469e0bSBalaji T K MODULE_AUTHOR("Balaji T K <balajitk@ti.com>"); 25311469e0bSBalaji T K MODULE_DESCRIPTION("pbias voltage regulator"); 25411469e0bSBalaji T K MODULE_LICENSE("GPL"); 25511469e0bSBalaji T K MODULE_ALIAS("platform:pbias-regulator"); 256