1 // SPDX-License-Identifier: GPL-2.0+ 2 // 3 // Copyright (c) 2019 Mantas Pucka <mantas@8devices.com> 4 // Copyright (c) 2019 Robert Marko <robert.marko@sartura.hr> 5 // 6 // Driver for IPQ4019 SD/MMC controller's I/O LDO voltage regulator 7 8 #include <linux/io.h> 9 #include <linux/module.h> 10 #include <linux/of.h> 11 #include <linux/platform_device.h> 12 #include <linux/regmap.h> 13 #include <linux/regulator/driver.h> 14 #include <linux/regulator/machine.h> 15 #include <linux/regulator/of_regulator.h> 16 17 static const unsigned int ipq4019_vmmc_voltages[] = { 18 1500000, 1800000, 2500000, 3000000, 19 }; 20 21 static const struct regulator_ops ipq4019_regulator_voltage_ops = { 22 .list_voltage = regulator_list_voltage_table, 23 .map_voltage = regulator_map_voltage_ascend, 24 .get_voltage_sel = regulator_get_voltage_sel_regmap, 25 .set_voltage_sel = regulator_set_voltage_sel_regmap, 26 }; 27 28 static const struct regulator_desc vmmc_regulator = { 29 .name = "vmmcq", 30 .ops = &ipq4019_regulator_voltage_ops, 31 .type = REGULATOR_VOLTAGE, 32 .owner = THIS_MODULE, 33 .volt_table = ipq4019_vmmc_voltages, 34 .n_voltages = ARRAY_SIZE(ipq4019_vmmc_voltages), 35 .vsel_reg = 0, 36 .vsel_mask = 0x3, 37 }; 38 39 static const struct regmap_config ipq4019_vmmcq_regmap_config = { 40 .reg_bits = 32, 41 .reg_stride = 4, 42 .val_bits = 32, 43 }; 44 45 static int ipq4019_regulator_probe(struct platform_device *pdev) 46 { 47 struct device *dev = &pdev->dev; 48 struct regulator_init_data *init_data; 49 struct regulator_config cfg = {}; 50 struct regulator_dev *rdev; 51 struct regmap *rmap; 52 void __iomem *base; 53 54 init_data = of_get_regulator_init_data(dev, dev->of_node, 55 &vmmc_regulator); 56 if (!init_data) 57 return -EINVAL; 58 59 base = devm_platform_ioremap_resource(pdev, 0); 60 if (IS_ERR(base)) 61 return PTR_ERR(base); 62 63 rmap = devm_regmap_init_mmio(dev, base, &ipq4019_vmmcq_regmap_config); 64 if (IS_ERR(rmap)) 65 return PTR_ERR(rmap); 66 67 cfg.dev = dev; 68 cfg.init_data = init_data; 69 cfg.of_node = dev->of_node; 70 cfg.regmap = rmap; 71 72 rdev = devm_regulator_register(dev, &vmmc_regulator, &cfg); 73 if (IS_ERR(rdev)) { 74 dev_err(dev, "Failed to register regulator: %ld\n", 75 PTR_ERR(rdev)); 76 return PTR_ERR(rdev); 77 } 78 platform_set_drvdata(pdev, rdev); 79 80 return 0; 81 } 82 83 static const struct of_device_id regulator_ipq4019_of_match[] = { 84 { .compatible = "qcom,vqmmc-ipq4019-regulator", }, 85 {}, 86 }; 87 MODULE_DEVICE_TABLE(of, regulator_ipq4019_of_match); 88 89 static struct platform_driver ipq4019_regulator_driver = { 90 .probe = ipq4019_regulator_probe, 91 .driver = { 92 .name = "vqmmc-ipq4019-regulator", 93 .probe_type = PROBE_PREFER_ASYNCHRONOUS, 94 .of_match_table = of_match_ptr(regulator_ipq4019_of_match), 95 }, 96 }; 97 module_platform_driver(ipq4019_regulator_driver); 98 99 MODULE_LICENSE("GPL"); 100 MODULE_AUTHOR("Mantas Pucka <mantas@8devices.com>"); 101 MODULE_DESCRIPTION("IPQ4019 VQMMC voltage regulator"); 102