* Copyright (C) 2017 Maxim Integrated
*/
+#include <linux/array_size.h>
#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/time64.h>
+#include <linux/types.h>
#include <linux/iio/driver.h>
#include <linux/iio/iio.h>
};
struct ds4424_data {
- struct i2c_client *client;
- struct mutex lock;
- uint8_t save[DS4424_MAX_DAC_CHANNELS];
+ struct regmap *regmap;
struct regulator *vcc_reg;
- uint8_t raw[DS4424_MAX_DAC_CHANNELS];
const struct ds4424_chip_info *chip_info;
};
DS4424_CHANNEL(3),
};
-static int ds4424_get_value(struct iio_dev *indio_dev,
- int *val, int channel)
-{
- struct ds4424_data *data = iio_priv(indio_dev);
- int ret;
+static const struct regmap_range ds44x2_ranges[] = {
+ regmap_reg_range(DS4424_DAC_ADDR(0), DS4424_DAC_ADDR(1)),
+};
- mutex_lock(&data->lock);
- ret = i2c_smbus_read_byte_data(data->client, DS4424_DAC_ADDR(channel));
- if (ret < 0)
- goto fail;
+static const struct regmap_range ds44x4_ranges[] = {
+ regmap_reg_range(DS4424_DAC_ADDR(0), DS4424_DAC_ADDR(3)),
+};
- *val = ret;
+static const struct regmap_access_table ds44x2_table = {
+ .yes_ranges = ds44x2_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ds44x2_ranges),
+};
-fail:
- mutex_unlock(&data->lock);
- return ret;
-}
+static const struct regmap_access_table ds44x4_table = {
+ .yes_ranges = ds44x4_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ds44x4_ranges),
+};
-static int ds4424_set_value(struct iio_dev *indio_dev,
- int val, struct iio_chan_spec const *chan)
+static const struct regmap_config ds44x2_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .cache_type = REGCACHE_MAPLE,
+ .max_register = DS4424_DAC_ADDR(1),
+ .rd_table = &ds44x2_table,
+ .wr_table = &ds44x2_table,
+};
+
+static const struct regmap_config ds44x4_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .cache_type = REGCACHE_MAPLE,
+ .max_register = DS4424_DAC_ADDR(3),
+ .rd_table = &ds44x4_table,
+ .wr_table = &ds44x4_table,
+};
+
+static int ds4424_init_regmap(struct i2c_client *client,
+ struct iio_dev *indio_dev)
{
struct ds4424_data *data = iio_priv(indio_dev);
+ const struct regmap_config *regmap_config;
+ u8 vals[DS4424_MAX_DAC_CHANNELS];
int ret;
- mutex_lock(&data->lock);
- ret = i2c_smbus_write_byte_data(data->client,
- DS4424_DAC_ADDR(chan->channel), val);
- if (ret < 0)
- goto fail;
+ if (indio_dev->num_channels == DS4424_MAX_DAC_CHANNELS)
+ regmap_config = &ds44x4_regmap_config;
+ else
+ regmap_config = &ds44x2_regmap_config;
- data->raw[chan->channel] = val;
+ data->regmap = devm_regmap_init_i2c(client, regmap_config);
+ if (IS_ERR(data->regmap))
+ return dev_err_probe(&client->dev, PTR_ERR(data->regmap),
+ "Failed to init regmap.\n");
-fail:
- mutex_unlock(&data->lock);
- return ret;
+ /*
+ * Prime the cache with the bootloader's configuration.
+ * regmap_bulk_read() will automatically populate the cache with
+ * the values read from the hardware.
+ */
+ ret = regmap_bulk_read(data->regmap, DS4424_DAC_ADDR(0), vals,
+ indio_dev->num_channels);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "Failed to read hardware values\n");
+
+ return 0;
}
static int ds4424_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct ds4424_data *data = iio_priv(indio_dev);
- int ret, regval;
+ unsigned int regval;
+ int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = ds4424_get_value(indio_dev, ®val, chan->channel);
+ ret = regmap_read(data->regmap, DS4424_DAC_ADDR(chan->channel),
+ ®val);
if (ret < 0) {
dev_err_ratelimited(indio_dev->dev.parent,
"Failed to read channel %d: %pe\n",
if (val > 0)
abs_val |= DS4424_DAC_SOURCE;
- return ds4424_set_value(indio_dev, abs_val, chan);
+ return regmap_write(data->regmap, DS4424_DAC_ADDR(chan->channel),
+ abs_val);
default:
return -EINVAL;
}
}
-static int ds4424_verify_chip(struct iio_dev *indio_dev)
-{
- int ret, val;
-
- ret = ds4424_get_value(indio_dev, &val, 0);
- if (ret < 0)
- dev_err(&indio_dev->dev,
- "%s failed. ret: %d\n", __func__, ret);
-
- return ret;
-}
-
static int ds4424_suspend(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ds4424_data *data = iio_priv(indio_dev);
- int ret = 0;
- int i;
-
- for (i = 0; i < indio_dev->num_channels; i++) {
- data->save[i] = data->raw[i];
- ret = ds4424_set_value(indio_dev, 0,
- &indio_dev->channels[i]);
- if (ret < 0)
- return ret;
+ u8 zero_buf[DS4424_MAX_DAC_CHANNELS] = { };
+ int ret;
+
+ /* Disable all outputs, bypass cache so the '0' isn't saved */
+ regcache_cache_bypass(data->regmap, true);
+ ret = regmap_bulk_write(data->regmap, DS4424_DAC_ADDR(0),
+ zero_buf, indio_dev->num_channels);
+ regcache_cache_bypass(data->regmap, false);
+ if (ret) {
+ dev_err(dev, "Failed to zero outputs: %pe\n", ERR_PTR(ret));
+ return ret;
}
- return ret;
+
+ regcache_cache_only(data->regmap, true);
+ regcache_mark_dirty(data->regmap);
+
+ return 0;
}
static int ds4424_resume(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ds4424_data *data = iio_priv(indio_dev);
- int ret = 0;
- int i;
- for (i = 0; i < indio_dev->num_channels; i++) {
- ret = ds4424_set_value(indio_dev, data->save[i],
- &indio_dev->channels[i]);
- if (ret < 0)
- return ret;
- }
- return ret;
+ regcache_cache_only(data->regmap, false);
+ return regcache_sync(data->regmap);
}
static DEFINE_SIMPLE_DEV_PM_OPS(ds4424_pm_ops, ds4424_suspend, ds4424_resume);
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
- data->client = client;
indio_dev->name = chip_info->name;
data->chip_info = chip_info;
return dev_err_probe(&client->dev, PTR_ERR(data->vcc_reg),
"Failed to get vcc-supply regulator.\n");
- mutex_init(&data->lock);
ret = regulator_enable(data->vcc_reg);
if (ret < 0) {
dev_err(&client->dev,
*/
fsleep(1 * USEC_PER_MSEC);
- ret = ds4424_verify_chip(indio_dev);
- if (ret < 0)
- goto fail;
-
indio_dev->num_channels = chip_info->num_channels;
indio_dev->channels = ds4424_channels;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &ds4424_iio_info;
+ ret = ds4424_init_regmap(client, indio_dev);
+ if (ret)
+ goto fail;
+
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev,