#include <linux/mfd/s5m87xx/s5m-rtc.h>
#include <linux/regmap.h>
+#ifdef CONFIG_OF
+static struct of_device_id __devinitdata s5m87xx_pmic_dt_match[] = {
+ {.compatible = "samsung,s5m8767-pmic"},
+ {},
+};
+#endif
+
static struct mfd_cell s5m8751_devs[] = {
{
.name = "s5m8751-pmic",
.val_bits = 8,
};
+static inline int s5m87xx_i2c_get_driver_data(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+#ifdef CONFIG_OF
+ if (i2c->dev.of_node) {
+ const struct of_device_id *match;
+ match = of_match_node(s5m87xx_pmic_dt_match, i2c->dev.of_node);
+ return (int)match->data;
+ }
+#endif
+ return (int)id->driver_data;
+}
+
+#ifdef CONFIG_OF
+static struct s5m_platform_data *s5m87xx_i2c_parse_dt_pdata(struct device *dev)
+{
+ struct s5m_platform_data *pd;
+
+ pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+ if (!pd) {
+ dev_err(dev, "could not allocate memory for pdata\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ if (of_property_read_u32(dev->of_node, "s5m-core,device_type",
+ &pd->device_type)) {
+ dev_warn(dev, "no OF device_type property");
+ } else {
+ dev_dbg(dev, "OF device_type property = %u", pd->device_type);
+ }
+ return pd;
+}
+#else
+static struct s5m_platform_data *s5m8767_i2c_parse_dt_pdata(struct device *dev)
+{
+ return 0;
+}
+#endif
+
static int s5m87xx_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
s5m87xx->dev = &i2c->dev;
s5m87xx->i2c = i2c;
s5m87xx->irq = i2c->irq;
- s5m87xx->type = id->driver_data;
+ s5m87xx->type = s5m87xx_i2c_get_driver_data(i2c, id);
- if (pdata) {
- s5m87xx->device_type = pdata->device_type;
- s5m87xx->ono = pdata->ono;
- s5m87xx->irq_base = pdata->irq_base;
- s5m87xx->wakeup = pdata->wakeup;
+ if (s5m87xx->dev->of_node) {
+ pdata = s5m87xx_i2c_parse_dt_pdata(s5m87xx->dev);
+ if (IS_ERR(pdata)) {
+ ret = PTR_ERR(pdata);
+ goto err;
+ }
}
+ s5m87xx->pdata = pdata;
+
+ if (!pdata) {
+ ret = -ENODEV;
+ dev_warn(s5m87xx->dev, "No platform data found\n");
+ goto err;
+ }
+
+ s5m87xx->device_type = pdata->device_type;
+ /* TODO(tbroch): address whether we want this addtional interrupt node
+ and add it to DT parsing if yes.
+ */
+ s5m87xx->ono = pdata->ono;
+ /* TODO(tbroch): remove hack below and parse irq_base via DT */
+ s5m87xx->irq_base = pdata->irq_base = MAX77686_IRQ_BASE;
+#ifdef OF_CONFIG
+ s5m87xx->wakeup = i2c->flags & I2C_CLIENT_WAKE;
+#else
+ s5m87xx->wakeup = pdata->wakeup;
+#endif
s5m87xx->regmap = regmap_init_i2c(i2c, &s5m_regmap_config);
if (IS_ERR(s5m87xx->regmap)) {
.driver = {
.name = "s5m87xx",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(s5m87xx_pmic_dt_match),
},
.probe = s5m87xx_i2c_probe,
.remove = s5m87xx_i2c_remove,
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/mfd/s5m87xx/s5m-core.h>
#include <linux/mfd/s5m87xx/s5m-pmic.h>
+#define S5M8767_OPMODE_MASK 0x3
+
struct s5m8767_info {
struct device *dev;
struct s5m87xx_dev *iodev;
regulator_desc_buck(9),
};
+#ifdef CONFIG_OF
+static int s5m8767_pmic_dt_parse_pdata(struct s5m87xx_dev *iodev,
+ struct s5m_platform_data *pdata)
+{
+ struct device_node *pmic_np, *regulators_np, *reg_np;
+ struct s5m_regulator_data *rdata;
+ unsigned int i;
+
+ pmic_np = iodev->dev->of_node;
+ if (!pmic_np) {
+ dev_err(iodev->dev, "could not find pmic sub-node\n");
+ return -ENODEV;
+ }
+
+ regulators_np = of_find_node_by_name(pmic_np, "voltage-regulators");
+ if (!regulators_np) {
+ dev_err(iodev->dev, "could not find regulators sub-node\n");
+ return -EINVAL;
+ }
+
+ /* count the number of regulators to be supported in pmic */
+ pdata->num_regulators = 0;
+ for_each_child_of_node(regulators_np, reg_np)
+ pdata->num_regulators++;
+
+ rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) *
+ pdata->num_regulators, GFP_KERNEL);
+ if (!rdata) {
+ dev_err(iodev->dev,
+ "could not allocate memory for regulator data\n");
+ return -ENOMEM;
+ }
+
+ pdata->regulators = rdata;
+ for_each_child_of_node(regulators_np, reg_np) {
+ for (i = 0; i < ARRAY_SIZE(regulators); i++)
+ if (!of_node_cmp(reg_np->name, regulators[i].name))
+ break;
+
+ if (i == ARRAY_SIZE(regulators)) {
+ dev_warn(iodev->dev,
+ "No configuration data for regulator %s\n",
+ reg_np->name);
+ continue;
+ }
+
+ rdata->id = i;
+ rdata->initdata = of_get_regulator_init_data(
+ iodev->dev, reg_np);
+ rdata->reg_node = reg_np;
+ if (of_property_read_u32(reg_np, "reg_op_mode",
+ &rdata->reg_op_mode)) {
+ dev_warn(iodev->dev, "no op_mode property property at %s\n",
+ reg_np->full_name);
+ /*
+ * Set operating mode to NORMAL "ON" as default. The
+ * 32KHz clocks are being turned on and kept on by
+ * default, so the below mode setting does not impact
+ * it.
+ */
+ rdata->reg_op_mode = S5M8767_OPMODE_MASK;
+ }
+ rdata++;
+ }
+
+ if (!of_property_read_u32(pmic_np, "s5m8767,buck_ramp_delay", &i))
+ pdata->buck_ramp_delay = i & 0xf;
+
+ if (of_get_property(pmic_np, "s5m8767,buck2_ramp_enable", NULL))
+ pdata->buck2_ramp_enable = 1;
+
+ if (of_get_property(pmic_np, "s5m8767,buck3_ramp_enable", NULL))
+ pdata->buck3_ramp_enable = 1;
+
+ if (of_get_property(pmic_np, "s5m8767,buck4_ramp_enable", NULL))
+ pdata->buck4_ramp_enable = 1;
+
+ return 0;
+}
+#else
+static int s5m8767_pmic_dt_parse_pdata(struct s5m87xx_dev *iodev,
+ struct s5m_platform_data *pdata)
+{
+ return 0;
+}
+#endif /* CONFIG_OF */
+
static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
{
struct s5m87xx_dev *iodev = dev_get_drvdata(pdev->dev.parent);
- struct s5m_platform_data *pdata = dev_get_platdata(iodev->dev);
+ struct s5m_platform_data *pdata = iodev->pdata;
struct regulator_dev **rdev;
struct s5m8767_info *s5m8767;
int i, ret, size;
return -ENODEV;
}
+ if (iodev->dev->of_node) {
+ ret = s5m8767_pmic_dt_parse_pdata(iodev, pdata);
+ if (ret)
+ return ret;
+ }
+
if (pdata->buck2_gpiodvs) {
if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) {
dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n");
if (!s5m8767)
return -ENOMEM;
- size = sizeof(struct regulator_dev *) * (S5M8767_REG_MAX - 2);
+ if (!pdata->num_regulators)
+ pdata->num_regulators = S5M8767_REG_MAX - 2;
+
+ size = sizeof(struct regulator_dev *) * pdata->num_regulators;
s5m8767->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
if (!s5m8767->rdev)
return -ENOMEM;
rdev = s5m8767->rdev;
s5m8767->dev = &pdev->dev;
s5m8767->iodev = iodev;
- s5m8767->num_regulators = S5M8767_REG_MAX - 2;
+ s5m8767->num_regulators = pdata->num_regulators;
platform_set_drvdata(pdev, s5m8767);
s5m8767->buck_gpioindex = pdata->buck_default_idx;
(desc->max - desc->min) / desc->step + 1;
rdev[i] = regulator_register(®ulators[id], s5m8767->dev,
- pdata->regulators[i].initdata, s5m8767, NULL);
+ pdata->regulators[i].initdata,
+ s5m8767,
+ pdata->regulators[i].reg_node);
if (IS_ERR(rdev[i])) {
ret = PTR_ERR(rdev[i]);
dev_err(s5m8767->dev, "regulator init failed for %d\n",