Commit 11f24823 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'regulator/topic/da9210',...

Merge remote-tracking branches 'regulator/topic/da9210', 'regulator/topic/da9211', 'regulator/topic/fan53555', 'regulator/topic/isl9305' and 'regulator/topic/list' into regulator-next
...@@ -5,6 +5,10 @@ Required properties: ...@@ -5,6 +5,10 @@ Required properties:
- compatible: must be "dlg,da9210" - compatible: must be "dlg,da9210"
- reg: the i2c slave address of the regulator. It should be 0x68. - reg: the i2c slave address of the regulator. It should be 0x68.
Optional properties:
- interrupts: a reference to the DA9210 interrupt, if available.
Any standard regulator properties can be used to configure the single da9210 Any standard regulator properties can be used to configure the single da9210
DCDC. DCDC.
......
* Dialog Semiconductor DA9211/DA9213 Voltage Regulator * Dialog Semiconductor DA9211/DA9213/DA9215 Voltage Regulator
Required properties: Required properties:
- compatible: "dlg,da9211" or "dlg,da9213". - compatible: "dlg,da9211" or "dlg,da9213" or "dlg,da9215"
- reg: I2C slave address, usually 0x68. - reg: I2C slave address, usually 0x68.
- interrupts: the interrupt outputs of the controller - interrupts: the interrupt outputs of the controller
- regulators: A node that houses a sub-node for each regulator within the - regulators: A node that houses a sub-node for each regulator within the
...@@ -66,3 +66,31 @@ Example 2) DA9213 ...@@ -66,3 +66,31 @@ Example 2) DA9213
}; };
}; };
}; };
Example 3) DA9215
pmic: da9215@68 {
compatible = "dlg,da9215";
reg = <0x68>;
interrupts = <3 27>;
regulators {
BUCKA {
regulator-name = "VBUCKA";
regulator-min-microvolt = < 300000>;
regulator-max-microvolt = <1570000>;
regulator-min-microamp = <4000000>;
regulator-max-microamp = <7000000>;
enable-gpios = <&gpio 27 0>;
};
BUCKB {
regulator-name = "VBUCKB";
regulator-min-microvolt = < 300000>;
regulator-max-microvolt = <1570000>;
regulator-min-microamp = <4000000>;
regulator-max-microamp = <7000000>;
enable-gpios = <&gpio 17 0>;
};
};
};
...@@ -209,13 +209,13 @@ config REGULATOR_DA9210 ...@@ -209,13 +209,13 @@ config REGULATOR_DA9210
interface. interface.
config REGULATOR_DA9211 config REGULATOR_DA9211
tristate "Dialog Semiconductor DA9211/DA9212/DA9213/DA9214 regulator" tristate "Dialog Semiconductor DA9211/DA9212/DA9213/DA9214/DA9215 regulator"
depends on I2C depends on I2C
select REGMAP_I2C select REGMAP_I2C
help help
Say y here to support for the Dialog Semiconductor DA9211/DA9212 Say y here to support for the Dialog Semiconductor DA9211/DA9212
/DA9213/DA9214. /DA9213/DA9214/DA9215.
The DA9211/DA9212/DA9213/DA9214 is a multi-phase synchronous The DA9211/DA9212/DA9213/DA9214/DA9215 is a multi-phase synchronous
step down converter 12A or 16A DC-DC Buck controlled through an I2C step down converter 12A or 16A DC-DC Buck controlled through an I2C
interface. interface.
......
...@@ -111,6 +111,11 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, ...@@ -111,6 +111,11 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
const char *supply_name); const char *supply_name);
static void _regulator_put(struct regulator *regulator); static void _regulator_put(struct regulator *regulator);
static struct regulator_dev *dev_to_rdev(struct device *dev)
{
return container_of(dev, struct regulator_dev, dev);
}
static const char *rdev_get_name(struct regulator_dev *rdev) static const char *rdev_get_name(struct regulator_dev *rdev)
{ {
if (rdev->constraints && rdev->constraints->name) if (rdev->constraints && rdev->constraints->name)
...@@ -1612,14 +1617,15 @@ static void _regulator_put(struct regulator *regulator) ...@@ -1612,14 +1617,15 @@ static void _regulator_put(struct regulator *regulator)
if (regulator->dev) if (regulator->dev)
sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name);
mutex_lock(&rdev->mutex); mutex_lock(&rdev->mutex);
kfree(regulator->supply_name);
list_del(&regulator->list); list_del(&regulator->list);
kfree(regulator);
rdev->open_count--; rdev->open_count--;
rdev->exclusive = 0; rdev->exclusive = 0;
mutex_unlock(&rdev->mutex); mutex_unlock(&rdev->mutex);
kfree(regulator->supply_name);
kfree(regulator);
module_put(rdev->owner); module_put(rdev->owner);
} }
...@@ -3608,6 +3614,9 @@ static const struct attribute_group *regulator_dev_groups[] = { ...@@ -3608,6 +3614,9 @@ static const struct attribute_group *regulator_dev_groups[] = {
static void regulator_dev_release(struct device *dev) static void regulator_dev_release(struct device *dev)
{ {
struct regulator_dev *rdev = dev_get_drvdata(dev); struct regulator_dev *rdev = dev_get_drvdata(dev);
kfree(rdev->constraints);
of_node_put(rdev->dev.of_node);
kfree(rdev); kfree(rdev);
} }
...@@ -3839,9 +3848,7 @@ void regulator_unregister(struct regulator_dev *rdev) ...@@ -3839,9 +3848,7 @@ void regulator_unregister(struct regulator_dev *rdev)
unset_regulator_supplies(rdev); unset_regulator_supplies(rdev);
list_del(&rdev->list); list_del(&rdev->list);
mutex_unlock(&regulator_list_mutex); mutex_unlock(&regulator_list_mutex);
kfree(rdev->constraints);
regulator_ena_gpio_free(rdev); regulator_ena_gpio_free(rdev);
of_node_put(rdev->dev.of_node);
device_unregister(&rdev->dev); device_unregister(&rdev->dev);
} }
EXPORT_SYMBOL_GPL(regulator_unregister); EXPORT_SYMBOL_GPL(regulator_unregister);
...@@ -4161,13 +4168,57 @@ static int __init regulator_init(void) ...@@ -4161,13 +4168,57 @@ static int __init regulator_init(void)
/* init early to allow our consumers to complete system booting */ /* init early to allow our consumers to complete system booting */
core_initcall(regulator_init); core_initcall(regulator_init);
static int __init regulator_init_complete(void) static int __init regulator_late_cleanup(struct device *dev, void *data)
{ {
struct regulator_dev *rdev; struct regulator_dev *rdev = dev_to_rdev(dev);
const struct regulator_ops *ops; const struct regulator_ops *ops = rdev->desc->ops;
struct regulation_constraints *c; struct regulation_constraints *c = rdev->constraints;
int enabled, ret; int enabled, ret;
if (c && c->always_on)
return 0;
if (c && !(c->valid_ops_mask & REGULATOR_CHANGE_STATUS))
return 0;
mutex_lock(&rdev->mutex);
if (rdev->use_count)
goto unlock;
/* If we can't read the status assume it's on. */
if (ops->is_enabled)
enabled = ops->is_enabled(rdev);
else
enabled = 1;
if (!enabled)
goto unlock;
if (have_full_constraints()) {
/* We log since this may kill the system if it goes
* wrong. */
rdev_info(rdev, "disabling\n");
ret = _regulator_do_disable(rdev);
if (ret != 0)
rdev_err(rdev, "couldn't disable: %d\n", ret);
} else {
/* The intention is that in future we will
* assume that full constraints are provided
* so warn even if we aren't going to do
* anything here.
*/
rdev_warn(rdev, "incomplete constraints, leaving on\n");
}
unlock:
mutex_unlock(&rdev->mutex);
return 0;
}
static int __init regulator_init_complete(void)
{
/* /*
* Since DT doesn't provide an idiomatic mechanism for * Since DT doesn't provide an idiomatic mechanism for
* enabling full constraints and since it's much more natural * enabling full constraints and since it's much more natural
...@@ -4177,58 +4228,13 @@ static int __init regulator_init_complete(void) ...@@ -4177,58 +4228,13 @@ static int __init regulator_init_complete(void)
if (of_have_populated_dt()) if (of_have_populated_dt())
has_full_constraints = true; has_full_constraints = true;
mutex_lock(&regulator_list_mutex);
/* If we have a full configuration then disable any regulators /* If we have a full configuration then disable any regulators
* we have permission to change the status for and which are * we have permission to change the status for and which are
* not in use or always_on. This is effectively the default * not in use or always_on. This is effectively the default
* for DT and ACPI as they have full constraints. * for DT and ACPI as they have full constraints.
*/ */
list_for_each_entry(rdev, &regulator_list, list) { class_for_each_device(&regulator_class, NULL, NULL,
ops = rdev->desc->ops; regulator_late_cleanup);
c = rdev->constraints;
if (c && c->always_on)
continue;
if (c && !(c->valid_ops_mask & REGULATOR_CHANGE_STATUS))
continue;
mutex_lock(&rdev->mutex);
if (rdev->use_count)
goto unlock;
/* If we can't read the status assume it's on. */
if (ops->is_enabled)
enabled = ops->is_enabled(rdev);
else
enabled = 1;
if (!enabled)
goto unlock;
if (have_full_constraints()) {
/* We log since this may kill the system if it
* goes wrong. */
rdev_info(rdev, "disabling\n");
ret = _regulator_do_disable(rdev);
if (ret != 0)
rdev_err(rdev, "couldn't disable: %d\n", ret);
} else {
/* The intention is that in future we will
* assume that full constraints are provided
* so warn even if we aren't going to do
* anything here.
*/
rdev_warn(rdev, "incomplete constraints, leaving on\n");
}
unlock:
mutex_unlock(&rdev->mutex);
}
mutex_unlock(&regulator_list_mutex);
return 0; return 0;
} }
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/regulator/driver.h> #include <linux/regulator/driver.h>
#include <linux/regulator/machine.h> #include <linux/regulator/machine.h>
...@@ -120,6 +122,55 @@ static int da9210_get_current_limit(struct regulator_dev *rdev) ...@@ -120,6 +122,55 @@ static int da9210_get_current_limit(struct regulator_dev *rdev)
return da9210_buck_limits[sel]; return da9210_buck_limits[sel];
} }
static irqreturn_t da9210_irq_handler(int irq, void *data)
{
struct da9210 *chip = data;
unsigned int val, handled = 0;
int error, ret = IRQ_NONE;
error = regmap_read(chip->regmap, DA9210_REG_EVENT_B, &val);
if (error < 0)
goto error_i2c;
if (val & DA9210_E_OVCURR) {
regulator_notifier_call_chain(chip->rdev,
REGULATOR_EVENT_OVER_CURRENT,
NULL);
handled |= DA9210_E_OVCURR;
}
if (val & DA9210_E_NPWRGOOD) {
regulator_notifier_call_chain(chip->rdev,
REGULATOR_EVENT_UNDER_VOLTAGE,
NULL);
handled |= DA9210_E_NPWRGOOD;
}
if (val & (DA9210_E_TEMP_WARN | DA9210_E_TEMP_CRIT)) {
regulator_notifier_call_chain(chip->rdev,
REGULATOR_EVENT_OVER_TEMP, NULL);
handled |= val & (DA9210_E_TEMP_WARN | DA9210_E_TEMP_CRIT);
}
if (val & DA9210_E_VMAX) {
regulator_notifier_call_chain(chip->rdev,
REGULATOR_EVENT_REGULATION_OUT,
NULL);
handled |= DA9210_E_VMAX;
}
if (handled) {
/* Clear handled events */
error = regmap_write(chip->regmap, DA9210_REG_EVENT_B, handled);
if (error < 0)
goto error_i2c;
ret = IRQ_HANDLED;
}
return ret;
error_i2c:
dev_err(regmap_get_device(chip->regmap), "I2C error : %d\n", error);
return ret;
}
/* /*
* I2C driver interface functions * I2C driver interface functions
*/ */
...@@ -168,6 +219,30 @@ static int da9210_i2c_probe(struct i2c_client *i2c, ...@@ -168,6 +219,30 @@ static int da9210_i2c_probe(struct i2c_client *i2c,
} }
chip->rdev = rdev; chip->rdev = rdev;
if (i2c->irq) {
error = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
da9210_irq_handler,
IRQF_TRIGGER_LOW |
IRQF_ONESHOT | IRQF_SHARED,
"da9210", chip);
if (error) {
dev_err(&i2c->dev, "Failed to request IRQ%u: %d\n",
i2c->irq, error);
return error;
}
error = regmap_update_bits(chip->regmap, DA9210_REG_MASK_B,
DA9210_M_OVCURR | DA9210_M_NPWRGOOD |
DA9210_M_TEMP_WARN |
DA9210_M_TEMP_CRIT | DA9210_M_VMAX, 0);
if (error < 0) {
dev_err(&i2c->dev, "Failed to update mask reg: %d\n",
error);
return error;
}
} else {
dev_warn(&i2c->dev, "No IRQ configured\n");
}
i2c_set_clientdata(i2c, chip); i2c_set_clientdata(i2c, chip);
......
/* /*
* da9211-regulator.c - Regulator device driver for DA9211/DA9213 * da9211-regulator.c - Regulator device driver for DA9211/DA9213/DA9215
* Copyright (C) 2014 Dialog Semiconductor Ltd. * Copyright (C) 2015 Dialog Semiconductor Ltd.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU Library General Public
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
/* DEVICE IDs */ /* DEVICE IDs */
#define DA9211_DEVICE_ID 0x22 #define DA9211_DEVICE_ID 0x22
#define DA9213_DEVICE_ID 0x23 #define DA9213_DEVICE_ID 0x23
#define DA9215_DEVICE_ID 0x24
#define DA9211_BUCK_MODE_SLEEP 1 #define DA9211_BUCK_MODE_SLEEP 1
#define DA9211_BUCK_MODE_SYNC 2 #define DA9211_BUCK_MODE_SYNC 2
...@@ -90,6 +91,13 @@ static const int da9213_current_limits[] = { ...@@ -90,6 +91,13 @@ static const int da9213_current_limits[] = {
3000000, 3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000, 3000000, 3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000,
4600000, 4800000, 5000000, 5200000, 5400000, 5600000, 5800000, 6000000 4600000, 4800000, 5000000, 5200000, 5400000, 5600000, 5800000, 6000000
}; };
/* Current limits for DA9215 buck (uA) indices
* corresponds with register values
*/
static const int da9215_current_limits[] = {
4000000, 4200000, 4400000, 4600000, 4800000, 5000000, 5200000, 5400000,
5600000, 5800000, 6000000, 6200000, 6400000, 6600000, 6800000, 7000000
};
static unsigned int da9211_buck_get_mode(struct regulator_dev *rdev) static unsigned int da9211_buck_get_mode(struct regulator_dev *rdev)
{ {
...@@ -157,6 +165,10 @@ static int da9211_set_current_limit(struct regulator_dev *rdev, int min, ...@@ -157,6 +165,10 @@ static int da9211_set_current_limit(struct regulator_dev *rdev, int min,
current_limits = da9213_current_limits; current_limits = da9213_current_limits;
max_size = ARRAY_SIZE(da9213_current_limits)-1; max_size = ARRAY_SIZE(da9213_current_limits)-1;
break; break;
case DA9215:
current_limits = da9215_current_limits;
max_size = ARRAY_SIZE(da9215_current_limits)-1;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
...@@ -189,6 +201,9 @@ static int da9211_get_current_limit(struct regulator_dev *rdev) ...@@ -189,6 +201,9 @@ static int da9211_get_current_limit(struct regulator_dev *rdev)
case DA9213: case DA9213:
current_limits = da9213_current_limits; current_limits = da9213_current_limits;
break; break;
case DA9215:
current_limits = da9215_current_limits;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
...@@ -350,13 +365,11 @@ static int da9211_regulator_init(struct da9211 *chip) ...@@ -350,13 +365,11 @@ static int da9211_regulator_init(struct da9211 *chip)
/* If configuration for 1/2 bucks is different between platform data /* If configuration for 1/2 bucks is different between platform data
* and the register, driver should exit. * and the register, driver should exit.
*/ */
if ((chip->pdata->num_buck == 2 && data == 0x40) if (chip->pdata->num_buck == 1 && data == 0x00)
|| (chip->pdata->num_buck == 1 && data == 0x00)) { chip->num_regulator = 1;
if (data == 0) else if (chip->pdata->num_buck == 2 && data != 0x00)
chip->num_regulator = 1; chip->num_regulator = 2;
else else {
chip->num_regulator = 2;
} else {
dev_err(chip->dev, "Configuration is mismatched\n"); dev_err(chip->dev, "Configuration is mismatched\n");
return -EINVAL; return -EINVAL;
} }
...@@ -438,6 +451,9 @@ static int da9211_i2c_probe(struct i2c_client *i2c, ...@@ -438,6 +451,9 @@ static int da9211_i2c_probe(struct i2c_client *i2c,
case DA9213_DEVICE_ID: case DA9213_DEVICE_ID:
chip->chip_id = DA9213; chip->chip_id = DA9213;
break; break;
case DA9215_DEVICE_ID:
chip->chip_id = DA9215;
break;
default: default:
dev_err(chip->dev, "Unsupported device id = 0x%x.\n", data); dev_err(chip->dev, "Unsupported device id = 0x%x.\n", data);
return -ENODEV; return -ENODEV;
...@@ -478,6 +494,7 @@ static int da9211_i2c_probe(struct i2c_client *i2c, ...@@ -478,6 +494,7 @@ static int da9211_i2c_probe(struct i2c_client *i2c,
static const struct i2c_device_id da9211_i2c_id[] = { static const struct i2c_device_id da9211_i2c_id[] = {
{"da9211", DA9211}, {"da9211", DA9211},
{"da9213", DA9213}, {"da9213", DA9213},
{"da9215", DA9215},
{}, {},
}; };
MODULE_DEVICE_TABLE(i2c, da9211_i2c_id); MODULE_DEVICE_TABLE(i2c, da9211_i2c_id);
...@@ -486,6 +503,7 @@ MODULE_DEVICE_TABLE(i2c, da9211_i2c_id); ...@@ -486,6 +503,7 @@ MODULE_DEVICE_TABLE(i2c, da9211_i2c_id);
static const struct of_device_id da9211_dt_ids[] = { static const struct of_device_id da9211_dt_ids[] = {
{ .compatible = "dlg,da9211", .data = &da9211_i2c_id[0] }, { .compatible = "dlg,da9211", .data = &da9211_i2c_id[0] },
{ .compatible = "dlg,da9213", .data = &da9211_i2c_id[1] }, { .compatible = "dlg,da9213", .data = &da9211_i2c_id[1] },
{ .compatible = "dlg,da9215", .data = &da9211_i2c_id[2] },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, da9211_dt_ids); MODULE_DEVICE_TABLE(of, da9211_dt_ids);
...@@ -504,5 +522,5 @@ static struct i2c_driver da9211_regulator_driver = { ...@@ -504,5 +522,5 @@ static struct i2c_driver da9211_regulator_driver = {
module_i2c_driver(da9211_regulator_driver); module_i2c_driver(da9211_regulator_driver);
MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>"); MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>");
MODULE_DESCRIPTION("Regulator device driver for Dialog DA9211/DA9213"); MODULE_DESCRIPTION("Regulator device driver for Dialog DA9211/DA9213/DA9215");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL");
/* /*
* da9211-regulator.h - Regulator definitions for DA9211/DA9213 * da9211-regulator.h - Regulator definitions for DA9211/DA9213/DA9215
* Copyright (C) 2014 Dialog Semiconductor Ltd. * Copyright (C) 2015 Dialog Semiconductor Ltd.
* *
* This library is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU General Public License
* License as published by the Free Software Foundation; either * as published by the Free Software Foundation; either version 2
* version 2 of the License, or (at your option) any later version. * of the License, or (at your option) any later version.
* *
* This library is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Library General Public License for more details. * GNU General Public License for more details.
*/ */
#ifndef __DA9211_REGISTERS_H__ #ifndef __DA9211_REGISTERS_H__
......
...@@ -439,6 +439,7 @@ static const struct i2c_device_id fan53555_id[] = { ...@@ -439,6 +439,7 @@ static const struct i2c_device_id fan53555_id[] = {
}, },
{ }, { },
}; };
MODULE_DEVICE_TABLE(i2c, fan53555_id);
static struct i2c_driver fan53555_regulator_driver = { static struct i2c_driver fan53555_regulator_driver = {
.driver = { .driver = {
......
...@@ -183,6 +183,7 @@ static const struct of_device_id isl9305_dt_ids[] = { ...@@ -183,6 +183,7 @@ static const struct of_device_id isl9305_dt_ids[] = {
{ .compatible = "isil,isl9305h" }, { .compatible = "isil,isl9305h" },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, isl9305_dt_ids);
#endif #endif
static const struct i2c_device_id isl9305_i2c_id[] = { static const struct i2c_device_id isl9305_i2c_id[] = {
......
/* /*
* da9211.h - Regulator device driver for DA9211/DA9213 * da9211.h - Regulator device driver for DA9211/DA9213/DA9215
* Copyright (C) 2014 Dialog Semiconductor Ltd. * Copyright (C) 2015 Dialog Semiconductor Ltd.
* *
* This library is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU General Public License
* License as published by the Free Software Foundation; either * as published by the Free Software Foundation; either version 2
* version 2 of the License, or (at your option) any later version. * of the License, or (at your option) any later version.
* *
* This library is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Library General Public License for more details. * GNU General Public License for more details.
*/ */
#ifndef __LINUX_REGULATOR_DA9211_H #ifndef __LINUX_REGULATOR_DA9211_H
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
enum da9211_chip_id { enum da9211_chip_id {
DA9211, DA9211,
DA9213, DA9213,
DA9215,
}; };
struct da9211_pdata { struct da9211_pdata {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment