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; 33c329061bSKishon Vijay Abraham I u32 disable_val; 3411469e0bSBalaji T K u32 vmode; 3511469e0bSBalaji T K unsigned int enable_time; 3611469e0bSBalaji T K char *name; 3727eae9d4SRavikumar Kattekola const unsigned int *pbias_volt_table; 3827eae9d4SRavikumar Kattekola int n_voltages; 3911469e0bSBalaji T K }; 4011469e0bSBalaji T K 41b9c93646SKishon Vijay Abraham I struct pbias_of_data { 42b9c93646SKishon Vijay Abraham I unsigned int offset; 43b9c93646SKishon Vijay Abraham I }; 44b9c93646SKishon Vijay Abraham I 4527eae9d4SRavikumar Kattekola static const unsigned int pbias_volt_table_3_0V[] = { 4660e8c1e3SAxel Lin 1800000, 4760e8c1e3SAxel Lin 3000000 4860e8c1e3SAxel Lin }; 4911469e0bSBalaji T K 5027eae9d4SRavikumar Kattekola static const unsigned int pbias_volt_table_3_3V[] = { 5127eae9d4SRavikumar Kattekola 1800000, 5227eae9d4SRavikumar Kattekola 3300000 5327eae9d4SRavikumar Kattekola }; 5427eae9d4SRavikumar Kattekola 55a180df71SBhumika Goyal static const struct regulator_ops pbias_regulator_voltage_ops = { 5660e8c1e3SAxel Lin .list_voltage = regulator_list_voltage_table, 5760e8c1e3SAxel Lin .get_voltage_sel = regulator_get_voltage_sel_regmap, 5860e8c1e3SAxel Lin .set_voltage_sel = regulator_set_voltage_sel_regmap, 5975dbf0a0SAxel Lin .enable = regulator_enable_regmap, 6060e8c1e3SAxel Lin .disable = regulator_disable_regmap, 6175dbf0a0SAxel Lin .is_enabled = regulator_is_enabled_regmap, 6211469e0bSBalaji T K }; 6311469e0bSBalaji T K 6411469e0bSBalaji T K static const struct pbias_reg_info pbias_mmc_omap2430 = { 6511469e0bSBalaji T K .enable = BIT(1), 6611469e0bSBalaji T K .enable_mask = BIT(1), 6711469e0bSBalaji T K .vmode = BIT(0), 68c329061bSKishon Vijay Abraham I .disable_val = 0, 6911469e0bSBalaji T K .enable_time = 100, 7027eae9d4SRavikumar Kattekola .pbias_volt_table = pbias_volt_table_3_0V, 7127eae9d4SRavikumar Kattekola .n_voltages = 2, 7211469e0bSBalaji T K .name = "pbias_mmc_omap2430" 7311469e0bSBalaji T K }; 7411469e0bSBalaji T K 7511469e0bSBalaji T K static const struct pbias_reg_info pbias_sim_omap3 = { 7611469e0bSBalaji T K .enable = BIT(9), 7711469e0bSBalaji T K .enable_mask = BIT(9), 7811469e0bSBalaji T K .vmode = BIT(8), 7911469e0bSBalaji T K .enable_time = 100, 8027eae9d4SRavikumar Kattekola .pbias_volt_table = pbias_volt_table_3_0V, 8127eae9d4SRavikumar Kattekola .n_voltages = 2, 8211469e0bSBalaji T K .name = "pbias_sim_omap3" 8311469e0bSBalaji T K }; 8411469e0bSBalaji T K 8511469e0bSBalaji T K static const struct pbias_reg_info pbias_mmc_omap4 = { 8611469e0bSBalaji T K .enable = BIT(26) | BIT(22), 8711469e0bSBalaji T K .enable_mask = BIT(26) | BIT(25) | BIT(22), 88c329061bSKishon Vijay Abraham I .disable_val = BIT(25), 8911469e0bSBalaji T K .vmode = BIT(21), 9011469e0bSBalaji T K .enable_time = 100, 9127eae9d4SRavikumar Kattekola .pbias_volt_table = pbias_volt_table_3_0V, 9227eae9d4SRavikumar Kattekola .n_voltages = 2, 9311469e0bSBalaji T K .name = "pbias_mmc_omap4" 9411469e0bSBalaji T K }; 9511469e0bSBalaji T K 9611469e0bSBalaji T K static const struct pbias_reg_info pbias_mmc_omap5 = { 9711469e0bSBalaji T K .enable = BIT(27) | BIT(26), 9811469e0bSBalaji T K .enable_mask = BIT(27) | BIT(25) | BIT(26), 99c329061bSKishon Vijay Abraham I .disable_val = BIT(25), 10011469e0bSBalaji T K .vmode = BIT(21), 10111469e0bSBalaji T K .enable_time = 100, 10227eae9d4SRavikumar Kattekola .pbias_volt_table = pbias_volt_table_3_3V, 10327eae9d4SRavikumar Kattekola .n_voltages = 2, 10411469e0bSBalaji T K .name = "pbias_mmc_omap5" 10511469e0bSBalaji T K }; 10611469e0bSBalaji T K 10711469e0bSBalaji T K static struct of_regulator_match pbias_matches[] = { 10811469e0bSBalaji T K { .name = "pbias_mmc_omap2430", .driver_data = (void *)&pbias_mmc_omap2430}, 10911469e0bSBalaji T K { .name = "pbias_sim_omap3", .driver_data = (void *)&pbias_sim_omap3}, 11011469e0bSBalaji T K { .name = "pbias_mmc_omap4", .driver_data = (void *)&pbias_mmc_omap4}, 11111469e0bSBalaji T K { .name = "pbias_mmc_omap5", .driver_data = (void *)&pbias_mmc_omap5}, 11211469e0bSBalaji T K }; 11311469e0bSBalaji T K #define PBIAS_NUM_REGS ARRAY_SIZE(pbias_matches) 11411469e0bSBalaji T K 115b9c93646SKishon Vijay Abraham I /* Offset from SCM general area (and syscon) base */ 116b9c93646SKishon Vijay Abraham I 117b9c93646SKishon Vijay Abraham I static const struct pbias_of_data pbias_of_data_omap2 = { 118b9c93646SKishon Vijay Abraham I .offset = 0x230, 119b9c93646SKishon Vijay Abraham I }; 120b9c93646SKishon Vijay Abraham I 121b9c93646SKishon Vijay Abraham I static const struct pbias_of_data pbias_of_data_omap3 = { 122b9c93646SKishon Vijay Abraham I .offset = 0x2b0, 123b9c93646SKishon Vijay Abraham I }; 124b9c93646SKishon Vijay Abraham I 125b9c93646SKishon Vijay Abraham I static const struct pbias_of_data pbias_of_data_omap4 = { 126b9c93646SKishon Vijay Abraham I .offset = 0x60, 127b9c93646SKishon Vijay Abraham I }; 128b9c93646SKishon Vijay Abraham I 129b9c93646SKishon Vijay Abraham I static const struct pbias_of_data pbias_of_data_omap5 = { 130b9c93646SKishon Vijay Abraham I .offset = 0x60, 131b9c93646SKishon Vijay Abraham I }; 132b9c93646SKishon Vijay Abraham I 133b9c93646SKishon Vijay Abraham I static const struct pbias_of_data pbias_of_data_dra7 = { 134b9c93646SKishon Vijay Abraham I .offset = 0xe00, 135b9c93646SKishon Vijay Abraham I }; 136b9c93646SKishon Vijay Abraham I 13711469e0bSBalaji T K static const struct of_device_id pbias_of_match[] = { 13811469e0bSBalaji T K { .compatible = "ti,pbias-omap", }, 139b9c93646SKishon Vijay Abraham I { .compatible = "ti,pbias-omap2", .data = &pbias_of_data_omap2, }, 140b9c93646SKishon Vijay Abraham I { .compatible = "ti,pbias-omap3", .data = &pbias_of_data_omap3, }, 141b9c93646SKishon Vijay Abraham I { .compatible = "ti,pbias-omap4", .data = &pbias_of_data_omap4, }, 142b9c93646SKishon Vijay Abraham I { .compatible = "ti,pbias-omap5", .data = &pbias_of_data_omap5, }, 143b9c93646SKishon Vijay Abraham I { .compatible = "ti,pbias-dra7", .data = &pbias_of_data_dra7, }, 14411469e0bSBalaji T K {}, 14511469e0bSBalaji T K }; 14611469e0bSBalaji T K MODULE_DEVICE_TABLE(of, pbias_of_match); 14711469e0bSBalaji T K 14811469e0bSBalaji T K static int pbias_regulator_probe(struct platform_device *pdev) 14911469e0bSBalaji T K { 15011469e0bSBalaji T K struct device_node *np = pdev->dev.of_node; 15111469e0bSBalaji T K struct resource *res; 15211469e0bSBalaji T K struct regulator_config cfg = { }; 153df8c542eSAxel Lin struct regulator_desc *desc; 154df8c542eSAxel Lin struct regulator_dev *rdev; 15511469e0bSBalaji T K struct regmap *syscon; 15611469e0bSBalaji T K const struct pbias_reg_info *info; 157df8c542eSAxel Lin int ret, count, idx; 158b9c93646SKishon Vijay Abraham I const struct pbias_of_data *data; 159b9c93646SKishon Vijay Abraham I unsigned int offset; 16011469e0bSBalaji T K 16111469e0bSBalaji T K count = of_regulator_match(&pdev->dev, np, pbias_matches, 16211469e0bSBalaji T K PBIAS_NUM_REGS); 16311469e0bSBalaji T K if (count < 0) 16411469e0bSBalaji T K return count; 16511469e0bSBalaji T K 166df8c542eSAxel Lin desc = devm_kcalloc(&pdev->dev, count, sizeof(*desc), GFP_KERNEL); 167df8c542eSAxel Lin if (!desc) 16811469e0bSBalaji T K return -ENOMEM; 16911469e0bSBalaji T K 17011469e0bSBalaji T K syscon = syscon_regmap_lookup_by_phandle(np, "syscon"); 17111469e0bSBalaji T K if (IS_ERR(syscon)) 17211469e0bSBalaji T K return PTR_ERR(syscon); 17311469e0bSBalaji T K 17441145b98SAxel Lin data = of_device_get_match_data(&pdev->dev); 17541145b98SAxel Lin if (data) { 176b9c93646SKishon Vijay Abraham I offset = data->offset; 177b9c93646SKishon Vijay Abraham I } else { 178b9c93646SKishon Vijay Abraham I res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 179b9c93646SKishon Vijay Abraham I if (!res) 180b9c93646SKishon Vijay Abraham I return -EINVAL; 181b9c93646SKishon Vijay Abraham I 182b9c93646SKishon Vijay Abraham I offset = res->start; 183b9c93646SKishon Vijay Abraham I dev_WARN(&pdev->dev, 184b9c93646SKishon Vijay Abraham I "using legacy dt data for pbias offset\n"); 185b9c93646SKishon Vijay Abraham I } 186b9c93646SKishon Vijay Abraham I 18760e8c1e3SAxel Lin cfg.regmap = syscon; 18811469e0bSBalaji T K cfg.dev = &pdev->dev; 18911469e0bSBalaji T K 190df8c542eSAxel Lin for (idx = 0; idx < PBIAS_NUM_REGS && count; idx++) { 19111469e0bSBalaji T K if (!pbias_matches[idx].init_data || 19211469e0bSBalaji T K !pbias_matches[idx].of_node) 19311469e0bSBalaji T K continue; 19411469e0bSBalaji T K 19511469e0bSBalaji T K info = pbias_matches[idx].driver_data; 19611469e0bSBalaji T K if (!info) 19711469e0bSBalaji T K return -ENODEV; 19811469e0bSBalaji T K 199df8c542eSAxel Lin desc->name = info->name; 200df8c542eSAxel Lin desc->owner = THIS_MODULE; 201df8c542eSAxel Lin desc->type = REGULATOR_VOLTAGE; 202df8c542eSAxel Lin desc->ops = &pbias_regulator_voltage_ops; 203df8c542eSAxel Lin desc->volt_table = info->pbias_volt_table; 204df8c542eSAxel Lin desc->n_voltages = info->n_voltages; 205df8c542eSAxel Lin desc->enable_time = info->enable_time; 206df8c542eSAxel Lin desc->vsel_reg = offset; 207df8c542eSAxel Lin desc->vsel_mask = info->vmode; 208df8c542eSAxel Lin desc->enable_reg = offset; 209df8c542eSAxel Lin desc->enable_mask = info->enable_mask; 210df8c542eSAxel Lin desc->enable_val = info->enable; 211df8c542eSAxel Lin desc->disable_val = info->disable_val; 21211469e0bSBalaji T K 21311469e0bSBalaji T K cfg.init_data = pbias_matches[idx].init_data; 21411469e0bSBalaji T K cfg.of_node = pbias_matches[idx].of_node; 21511469e0bSBalaji T K 216df8c542eSAxel Lin rdev = devm_regulator_register(&pdev->dev, desc, &cfg); 217df8c542eSAxel Lin if (IS_ERR(rdev)) { 218df8c542eSAxel Lin ret = PTR_ERR(rdev); 21911469e0bSBalaji T K dev_err(&pdev->dev, 22011469e0bSBalaji T K "Failed to register regulator: %d\n", ret); 22111469e0bSBalaji T K return ret; 22211469e0bSBalaji T K } 223df8c542eSAxel Lin desc++; 224df8c542eSAxel Lin count--; 225df8c542eSAxel Lin } 226df8c542eSAxel Lin 227df8c542eSAxel Lin return 0; 228df8c542eSAxel Lin } 22911469e0bSBalaji T K 23011469e0bSBalaji T K static struct platform_driver pbias_regulator_driver = { 23111469e0bSBalaji T K .probe = pbias_regulator_probe, 23211469e0bSBalaji T K .driver = { 23311469e0bSBalaji T K .name = "pbias-regulator", 23411469e0bSBalaji T K .of_match_table = of_match_ptr(pbias_of_match), 23511469e0bSBalaji T K }, 23611469e0bSBalaji T K }; 23711469e0bSBalaji T K 23811469e0bSBalaji T K module_platform_driver(pbias_regulator_driver); 23911469e0bSBalaji T K 24011469e0bSBalaji T K MODULE_AUTHOR("Balaji T K <balajitk@ti.com>"); 24111469e0bSBalaji T K MODULE_DESCRIPTION("pbias voltage regulator"); 24211469e0bSBalaji T K MODULE_LICENSE("GPL"); 24311469e0bSBalaji T K MODULE_ALIAS("platform:pbias-regulator"); 244