Unverified Commit 3c32a438 authored by Mark Brown's avatar Mark Brown
Browse files

regulator: Add device tree support to AD5398

Merge series from Isaac Scott <isaac.scott@ideasonboard.com>:

The AD5398 is a DAC that can be used to control current flow in circuits
in a wide variety of applications such as motor control, or in my case,
LED control. I found when working with the current driver that it did
not work for my use case. It transpired that it only had support for
platform_data, and didn't appear to be correctly implemented according
to the datasheet, which can be found here:

https://www.analog.com/media/en/technical-documentation/data-sheets/ad5398.pdf

One example of this is the "soft power-down" bit being referred to in
the driver as simply "enable", which gives the impression that the
setting that bit will allow current through the regulator, which it does
not.

This series allows the regulator to be given its constraints via the
device tree, and makes the function of the enable register much more
obvious.
parents f5aab043 5a6a4610
Loading
Loading
Loading
Loading
+18 −12
Original line number Diff line number Diff line
@@ -14,8 +14,9 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>

#define AD5398_CURRENT_EN_MASK	0x8000
#define AD5398_SW_POWER_DOWN	BIT(16)

struct ad5398_chip_info {
	struct i2c_client *client;
@@ -113,7 +114,7 @@ static int ad5398_set_current_limit(struct regulator_dev *rdev, int min_uA, int

	/* prepare register data */
	selector = (selector << chip->current_offset) & chip->current_mask;
	data = (unsigned short)selector | (data & AD5398_CURRENT_EN_MASK);
	data = (unsigned short)selector | (data & AD5398_SW_POWER_DOWN);

	/* write the new current value back as well as enable bit */
	ret = ad5398_write_reg(client, data);
@@ -132,10 +133,10 @@ static int ad5398_is_enabled(struct regulator_dev *rdev)
	if (ret < 0)
		return ret;

	if (data & AD5398_CURRENT_EN_MASK)
		return 1;
	else
	if (data & AD5398_SW_POWER_DOWN)
		return 0;
	else
		return 1;
}

static int ad5398_enable(struct regulator_dev *rdev)
@@ -149,10 +150,10 @@ static int ad5398_enable(struct regulator_dev *rdev)
	if (ret < 0)
		return ret;

	if (data & AD5398_CURRENT_EN_MASK)
	if (!(data & AD5398_SW_POWER_DOWN))
		return 0;

	data |= AD5398_CURRENT_EN_MASK;
	data &= ~AD5398_SW_POWER_DOWN;

	ret = ad5398_write_reg(client, data);

@@ -170,10 +171,10 @@ static int ad5398_disable(struct regulator_dev *rdev)
	if (ret < 0)
		return ret;

	if (!(data & AD5398_CURRENT_EN_MASK))
	if (data & AD5398_SW_POWER_DOWN)
		return 0;

	data &= ~AD5398_CURRENT_EN_MASK;
	data |= AD5398_SW_POWER_DOWN;

	ret = ad5398_write_reg(client, data);

@@ -221,15 +222,20 @@ static int ad5398_probe(struct i2c_client *client)
	const struct ad5398_current_data_format *df =
			(struct ad5398_current_data_format *)id->driver_data;

	if (!init_data)
		return -EINVAL;

	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
	if (!chip)
		return -ENOMEM;

	config.dev = &client->dev;
	if (client->dev.of_node)
		init_data = of_get_regulator_init_data(&client->dev,
						       client->dev.of_node,
						       &ad5398_reg);
	if (!init_data)
		return -EINVAL;

	config.init_data = init_data;
	config.of_node = client->dev.of_node;
	config.driver_data = chip;

	chip->client = client;