18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Copyright (c) 2019 Mantas Pucka <mantas@8devices.com> 48c2ecf20Sopenharmony_ci// Copyright (c) 2019 Robert Marko <robert.marko@sartura.hr> 58c2ecf20Sopenharmony_ci// 68c2ecf20Sopenharmony_ci// Driver for IPQ4019 SD/MMC controller's I/O LDO voltage regulator 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/io.h> 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/of.h> 118c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 128c2ecf20Sopenharmony_ci#include <linux/regmap.h> 138c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h> 148c2ecf20Sopenharmony_ci#include <linux/regulator/machine.h> 158c2ecf20Sopenharmony_ci#include <linux/regulator/of_regulator.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic const unsigned int ipq4019_vmmc_voltages[] = { 188c2ecf20Sopenharmony_ci 1500000, 1800000, 2500000, 3000000, 198c2ecf20Sopenharmony_ci}; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic const struct regulator_ops ipq4019_regulator_voltage_ops = { 228c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_table, 238c2ecf20Sopenharmony_ci .map_voltage = regulator_map_voltage_ascend, 248c2ecf20Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 258c2ecf20Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic const struct regulator_desc vmmc_regulator = { 298c2ecf20Sopenharmony_ci .name = "vmmcq", 308c2ecf20Sopenharmony_ci .ops = &ipq4019_regulator_voltage_ops, 318c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, 328c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 338c2ecf20Sopenharmony_ci .volt_table = ipq4019_vmmc_voltages, 348c2ecf20Sopenharmony_ci .n_voltages = ARRAY_SIZE(ipq4019_vmmc_voltages), 358c2ecf20Sopenharmony_ci .vsel_reg = 0, 368c2ecf20Sopenharmony_ci .vsel_mask = 0x3, 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic const struct regmap_config ipq4019_vmmcq_regmap_config = { 408c2ecf20Sopenharmony_ci .reg_bits = 32, 418c2ecf20Sopenharmony_ci .reg_stride = 4, 428c2ecf20Sopenharmony_ci .val_bits = 32, 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic int ipq4019_regulator_probe(struct platform_device *pdev) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 488c2ecf20Sopenharmony_ci struct regulator_init_data *init_data; 498c2ecf20Sopenharmony_ci struct regulator_config cfg = {}; 508c2ecf20Sopenharmony_ci struct regulator_dev *rdev; 518c2ecf20Sopenharmony_ci struct resource *res; 528c2ecf20Sopenharmony_ci struct regmap *rmap; 538c2ecf20Sopenharmony_ci void __iomem *base; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci init_data = of_get_regulator_init_data(dev, dev->of_node, 568c2ecf20Sopenharmony_ci &vmmc_regulator); 578c2ecf20Sopenharmony_ci if (!init_data) 588c2ecf20Sopenharmony_ci return -EINVAL; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 618c2ecf20Sopenharmony_ci base = devm_ioremap_resource(dev, res); 628c2ecf20Sopenharmony_ci if (IS_ERR(base)) 638c2ecf20Sopenharmony_ci return PTR_ERR(base); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci rmap = devm_regmap_init_mmio(dev, base, &ipq4019_vmmcq_regmap_config); 668c2ecf20Sopenharmony_ci if (IS_ERR(rmap)) 678c2ecf20Sopenharmony_ci return PTR_ERR(rmap); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci cfg.dev = dev; 708c2ecf20Sopenharmony_ci cfg.init_data = init_data; 718c2ecf20Sopenharmony_ci cfg.of_node = dev->of_node; 728c2ecf20Sopenharmony_ci cfg.regmap = rmap; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci rdev = devm_regulator_register(dev, &vmmc_regulator, &cfg); 758c2ecf20Sopenharmony_ci if (IS_ERR(rdev)) { 768c2ecf20Sopenharmony_ci dev_err(dev, "Failed to register regulator: %ld\n", 778c2ecf20Sopenharmony_ci PTR_ERR(rdev)); 788c2ecf20Sopenharmony_ci return PTR_ERR(rdev); 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, rdev); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return 0; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic const struct of_device_id regulator_ipq4019_of_match[] = { 868c2ecf20Sopenharmony_ci { .compatible = "qcom,vqmmc-ipq4019-regulator", }, 878c2ecf20Sopenharmony_ci {}, 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic struct platform_driver ipq4019_regulator_driver = { 918c2ecf20Sopenharmony_ci .probe = ipq4019_regulator_probe, 928c2ecf20Sopenharmony_ci .driver = { 938c2ecf20Sopenharmony_ci .name = "vqmmc-ipq4019-regulator", 948c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(regulator_ipq4019_of_match), 958c2ecf20Sopenharmony_ci }, 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_cimodule_platform_driver(ipq4019_regulator_driver); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1008c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mantas Pucka <mantas@8devices.com>"); 1018c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("IPQ4019 VQMMC voltage regulator"); 102