1167e3d8aSYong Shen /* 2167e3d8aSYong Shen * Regulator Driver for Freescale MC13xxx PMIC 3167e3d8aSYong Shen * 4167e3d8aSYong Shen * Copyright 2010 Yong Shen <yong.shen@linaro.org> 5167e3d8aSYong Shen * 6167e3d8aSYong Shen * Based on mc13783 regulator driver : 7167e3d8aSYong Shen * Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> 8167e3d8aSYong Shen * Copyright 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com> 9167e3d8aSYong Shen * 10167e3d8aSYong Shen * This program is free software; you can redistribute it and/or modify 11167e3d8aSYong Shen * it under the terms of the GNU General Public License version 2 as 12167e3d8aSYong Shen * published by the Free Software Foundation. 13167e3d8aSYong Shen * 14167e3d8aSYong Shen * Regs infos taken from mc13xxx drivers from freescale and mc13xxx.pdf file 15167e3d8aSYong Shen * from freescale 16167e3d8aSYong Shen */ 17167e3d8aSYong Shen 18167e3d8aSYong Shen #include <linux/mfd/mc13xxx.h> 19167e3d8aSYong Shen #include <linux/regulator/machine.h> 20167e3d8aSYong Shen #include <linux/regulator/driver.h> 2193bcb23bSShawn Guo #include <linux/regulator/of_regulator.h> 22167e3d8aSYong Shen #include <linux/platform_device.h> 23167e3d8aSYong Shen #include <linux/kernel.h> 24167e3d8aSYong Shen #include <linux/slab.h> 25167e3d8aSYong Shen #include <linux/init.h> 26167e3d8aSYong Shen #include <linux/err.h> 2765602c32SPaul Gortmaker #include <linux/module.h> 2893bcb23bSShawn Guo #include <linux/of.h> 29167e3d8aSYong Shen #include "mc13xxx.h" 30167e3d8aSYong Shen 31167e3d8aSYong Shen static int mc13xxx_regulator_enable(struct regulator_dev *rdev) 32167e3d8aSYong Shen { 33167e3d8aSYong Shen struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); 34167e3d8aSYong Shen struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; 35167e3d8aSYong Shen int id = rdev_get_id(rdev); 36167e3d8aSYong Shen int ret; 37167e3d8aSYong Shen 38167e3d8aSYong Shen dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); 39167e3d8aSYong Shen 40167e3d8aSYong Shen mc13xxx_lock(priv->mc13xxx); 41167e3d8aSYong Shen ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].reg, 42167e3d8aSYong Shen mc13xxx_regulators[id].enable_bit, 43167e3d8aSYong Shen mc13xxx_regulators[id].enable_bit); 44167e3d8aSYong Shen mc13xxx_unlock(priv->mc13xxx); 45167e3d8aSYong Shen 46167e3d8aSYong Shen return ret; 47167e3d8aSYong Shen } 48167e3d8aSYong Shen 49167e3d8aSYong Shen static int mc13xxx_regulator_disable(struct regulator_dev *rdev) 50167e3d8aSYong Shen { 51167e3d8aSYong Shen struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); 52167e3d8aSYong Shen struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; 53167e3d8aSYong Shen int id = rdev_get_id(rdev); 54167e3d8aSYong Shen int ret; 55167e3d8aSYong Shen 56167e3d8aSYong Shen dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); 57167e3d8aSYong Shen 58167e3d8aSYong Shen mc13xxx_lock(priv->mc13xxx); 59167e3d8aSYong Shen ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].reg, 60167e3d8aSYong Shen mc13xxx_regulators[id].enable_bit, 0); 61167e3d8aSYong Shen mc13xxx_unlock(priv->mc13xxx); 62167e3d8aSYong Shen 63167e3d8aSYong Shen return ret; 64167e3d8aSYong Shen } 65167e3d8aSYong Shen 66167e3d8aSYong Shen static int mc13xxx_regulator_is_enabled(struct regulator_dev *rdev) 67167e3d8aSYong Shen { 68167e3d8aSYong Shen struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); 69167e3d8aSYong Shen struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; 70167e3d8aSYong Shen int ret, id = rdev_get_id(rdev); 71167e3d8aSYong Shen unsigned int val; 72167e3d8aSYong Shen 73167e3d8aSYong Shen mc13xxx_lock(priv->mc13xxx); 74167e3d8aSYong Shen ret = mc13xxx_reg_read(priv->mc13xxx, mc13xxx_regulators[id].reg, &val); 75167e3d8aSYong Shen mc13xxx_unlock(priv->mc13xxx); 76167e3d8aSYong Shen 77167e3d8aSYong Shen if (ret) 78167e3d8aSYong Shen return ret; 79167e3d8aSYong Shen 80167e3d8aSYong Shen return (val & mc13xxx_regulators[id].enable_bit) != 0; 81167e3d8aSYong Shen } 82167e3d8aSYong Shen 83939b62d8SAxel Lin static int mc13xxx_regulator_set_voltage_sel(struct regulator_dev *rdev, 84939b62d8SAxel Lin unsigned selector) 85167e3d8aSYong Shen { 86167e3d8aSYong Shen struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); 87167e3d8aSYong Shen struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; 88939b62d8SAxel Lin int id = rdev_get_id(rdev); 89167e3d8aSYong Shen int ret; 90167e3d8aSYong Shen 91167e3d8aSYong Shen mc13xxx_lock(priv->mc13xxx); 92167e3d8aSYong Shen ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].vsel_reg, 93167e3d8aSYong Shen mc13xxx_regulators[id].vsel_mask, 94939b62d8SAxel Lin selector << mc13xxx_regulators[id].vsel_shift); 95167e3d8aSYong Shen mc13xxx_unlock(priv->mc13xxx); 96167e3d8aSYong Shen 97167e3d8aSYong Shen return ret; 98167e3d8aSYong Shen } 99167e3d8aSYong Shen 100167e3d8aSYong Shen static int mc13xxx_regulator_get_voltage(struct regulator_dev *rdev) 101167e3d8aSYong Shen { 102167e3d8aSYong Shen struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); 103167e3d8aSYong Shen struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; 104167e3d8aSYong Shen int ret, id = rdev_get_id(rdev); 105167e3d8aSYong Shen unsigned int val; 106167e3d8aSYong Shen 107167e3d8aSYong Shen dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); 108167e3d8aSYong Shen 109167e3d8aSYong Shen mc13xxx_lock(priv->mc13xxx); 110167e3d8aSYong Shen ret = mc13xxx_reg_read(priv->mc13xxx, 111167e3d8aSYong Shen mc13xxx_regulators[id].vsel_reg, &val); 112167e3d8aSYong Shen mc13xxx_unlock(priv->mc13xxx); 113167e3d8aSYong Shen 114167e3d8aSYong Shen if (ret) 115167e3d8aSYong Shen return ret; 116167e3d8aSYong Shen 117167e3d8aSYong Shen val = (val & mc13xxx_regulators[id].vsel_mask) 118167e3d8aSYong Shen >> mc13xxx_regulators[id].vsel_shift; 119167e3d8aSYong Shen 120167e3d8aSYong Shen dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val); 121167e3d8aSYong Shen 1223c24019dSAxel Lin BUG_ON(val >= mc13xxx_regulators[id].desc.n_voltages); 123167e3d8aSYong Shen 12434e74f39SAxel Lin return rdev->desc->volt_table[val]; 125167e3d8aSYong Shen } 126167e3d8aSYong Shen 127167e3d8aSYong Shen struct regulator_ops mc13xxx_regulator_ops = { 128167e3d8aSYong Shen .enable = mc13xxx_regulator_enable, 129167e3d8aSYong Shen .disable = mc13xxx_regulator_disable, 130167e3d8aSYong Shen .is_enabled = mc13xxx_regulator_is_enabled, 13134e74f39SAxel Lin .list_voltage = regulator_list_voltage_table, 132939b62d8SAxel Lin .set_voltage_sel = mc13xxx_regulator_set_voltage_sel, 133167e3d8aSYong Shen .get_voltage = mc13xxx_regulator_get_voltage, 134167e3d8aSYong Shen }; 1354d7071f1SMark Brown EXPORT_SYMBOL_GPL(mc13xxx_regulator_ops); 136167e3d8aSYong Shen 137167e3d8aSYong Shen int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, 138167e3d8aSYong Shen int max_uV, unsigned *selector) 139167e3d8aSYong Shen { 140167e3d8aSYong Shen int id = rdev_get_id(rdev); 141167e3d8aSYong Shen 142167e3d8aSYong Shen dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", 143167e3d8aSYong Shen __func__, id, min_uV, max_uV); 144167e3d8aSYong Shen 14534e74f39SAxel Lin if (min_uV <= rdev->desc->volt_table[0] && 14613407ea8SAxel Lin rdev->desc->volt_table[0] <= max_uV) { 14713407ea8SAxel Lin *selector = 0; 148167e3d8aSYong Shen return 0; 14913407ea8SAxel Lin } else { 150167e3d8aSYong Shen return -EINVAL; 151167e3d8aSYong Shen } 15213407ea8SAxel Lin } 1534d7071f1SMark Brown EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_set_voltage); 154167e3d8aSYong Shen 155167e3d8aSYong Shen struct regulator_ops mc13xxx_fixed_regulator_ops = { 156167e3d8aSYong Shen .enable = mc13xxx_regulator_enable, 157167e3d8aSYong Shen .disable = mc13xxx_regulator_disable, 158167e3d8aSYong Shen .is_enabled = mc13xxx_regulator_is_enabled, 15934e74f39SAxel Lin .list_voltage = regulator_list_voltage_table, 160167e3d8aSYong Shen .set_voltage = mc13xxx_fixed_regulator_set_voltage, 161167e3d8aSYong Shen }; 1624d7071f1SMark Brown EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_ops); 163167e3d8aSYong Shen 16493bcb23bSShawn Guo #ifdef CONFIG_OF 165a5023574SBill Pemberton int mc13xxx_get_num_regulators_dt(struct platform_device *pdev) 16693bcb23bSShawn Guo { 16786f66733SAxel Lin struct device_node *parent; 16886f66733SAxel Lin int num; 16993bcb23bSShawn Guo 17093bcb23bSShawn Guo of_node_get(pdev->dev.parent->of_node); 17193bcb23bSShawn Guo parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators"); 17293bcb23bSShawn Guo if (!parent) 17393bcb23bSShawn Guo return -ENODEV; 17493bcb23bSShawn Guo 17586f66733SAxel Lin num = of_get_child_count(parent); 176c92f5dd2SAxel Lin of_node_put(parent); 17793bcb23bSShawn Guo return num; 17893bcb23bSShawn Guo } 17953269163SDavid Miller EXPORT_SYMBOL_GPL(mc13xxx_get_num_regulators_dt); 18093bcb23bSShawn Guo 181a5023574SBill Pemberton struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( 18293bcb23bSShawn Guo struct platform_device *pdev, struct mc13xxx_regulator *regulators, 183eb0d8e7aSAlexander Shiyan int num_regulators) 18493bcb23bSShawn Guo { 18593bcb23bSShawn Guo struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); 18693bcb23bSShawn Guo struct mc13xxx_regulator_init_data *data, *p; 18793bcb23bSShawn Guo struct device_node *parent, *child; 1882c8a5dcaSMatt Sealey int i, parsed = 0; 1892c8a5dcaSMatt Sealey 19093bcb23bSShawn Guo of_node_get(pdev->dev.parent->of_node); 19193bcb23bSShawn Guo parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators"); 19293bcb23bSShawn Guo if (!parent) 19393bcb23bSShawn Guo return NULL; 19493bcb23bSShawn Guo 19593bcb23bSShawn Guo data = devm_kzalloc(&pdev->dev, sizeof(*data) * priv->num_regulators, 19693bcb23bSShawn Guo GFP_KERNEL); 197c92f5dd2SAxel Lin if (!data) { 198c92f5dd2SAxel Lin of_node_put(parent); 19993bcb23bSShawn Guo return NULL; 200c92f5dd2SAxel Lin } 201c92f5dd2SAxel Lin 20293bcb23bSShawn Guo p = data; 20393bcb23bSShawn Guo 20493bcb23bSShawn Guo for_each_child_of_node(parent, child) { 205eb0d8e7aSAlexander Shiyan int found = 0; 206eb0d8e7aSAlexander Shiyan 20793bcb23bSShawn Guo for (i = 0; i < num_regulators; i++) { 208eb0d8e7aSAlexander Shiyan if (!regulators[i].desc.name) 209eb0d8e7aSAlexander Shiyan continue; 21093bcb23bSShawn Guo if (!of_node_cmp(child->name, 21193bcb23bSShawn Guo regulators[i].desc.name)) { 21293bcb23bSShawn Guo p->id = i; 21393bcb23bSShawn Guo p->init_data = of_get_regulator_init_data( 21493bcb23bSShawn Guo &pdev->dev, child); 21593bcb23bSShawn Guo p->node = child; 21693bcb23bSShawn Guo p++; 2172c8a5dcaSMatt Sealey 2182c8a5dcaSMatt Sealey parsed++; 219eb0d8e7aSAlexander Shiyan found = 1; 22093bcb23bSShawn Guo break; 22193bcb23bSShawn Guo } 22293bcb23bSShawn Guo } 223eb0d8e7aSAlexander Shiyan 224eb0d8e7aSAlexander Shiyan if (!found) 225eb0d8e7aSAlexander Shiyan dev_warn(&pdev->dev, 226eb0d8e7aSAlexander Shiyan "Unknown regulator: %s\n", child->name); 22793bcb23bSShawn Guo } 228c92f5dd2SAxel Lin of_node_put(parent); 22993bcb23bSShawn Guo 230eb0d8e7aSAlexander Shiyan priv->num_regulators = parsed; 231eb0d8e7aSAlexander Shiyan 23293bcb23bSShawn Guo return data; 23393bcb23bSShawn Guo } 23453269163SDavid Miller EXPORT_SYMBOL_GPL(mc13xxx_parse_regulators_dt); 23593bcb23bSShawn Guo #endif 23693bcb23bSShawn Guo 237167e3d8aSYong Shen MODULE_LICENSE("GPL v2"); 238167e3d8aSYong Shen MODULE_AUTHOR("Yong Shen <yong.shen@linaro.org>"); 239167e3d8aSYong Shen MODULE_DESCRIPTION("Regulator Driver for Freescale MC13xxx PMIC"); 240167e3d8aSYong Shen MODULE_ALIAS("mc13xxx-regulator-core"); 241