diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index db9f5c711b3d..cd4870b65415 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -408,6 +408,7 @@ config DPOT_DAC config DS4424 tristate "Maxim Integrated DS4422/DS4424 DAC driver" depends on I2C + select REGMAP_I2C help If you say yes here you get support for Maxim chips DS4422, DS4424. diff --git a/drivers/iio/dac/ds4424.c b/drivers/iio/dac/ds4424.c index 4eff052c2b61..ee53614301c6 100644 --- a/drivers/iio/dac/ds4424.c +++ b/drivers/iio/dac/ds4424.c @@ -5,14 +5,17 @@ * Copyright (C) 2017 Maxim Integrated */ +#include #include #include #include #include #include #include +#include #include #include +#include #include #include @@ -66,11 +69,8 @@ static const struct ds4424_chip_info ds4424_info = { }; 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; }; @@ -81,41 +81,72 @@ static const struct iio_chan_spec ds4424_channels[] = { DS4424_CHANNEL(3), }; -static int ds4424_get_value(struct iio_dev *indio_dev, - int *val, int channel) +static const struct regmap_range ds44x2_ranges[] = { + regmap_reg_range(DS4424_DAC_ADDR(0), DS4424_DAC_ADDR(1)), +}; + +static const struct regmap_range ds44x4_ranges[] = { + regmap_reg_range(DS4424_DAC_ADDR(0), DS4424_DAC_ADDR(3)), +}; + +static const struct regmap_access_table ds44x2_table = { + .yes_ranges = ds44x2_ranges, + .n_yes_ranges = ARRAY_SIZE(ds44x2_ranges), +}; + +static const struct regmap_access_table ds44x4_table = { + .yes_ranges = ds44x4_ranges, + .n_yes_ranges = ARRAY_SIZE(ds44x4_ranges), +}; + +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_read_byte_data(data->client, DS4424_DAC_ADDR(channel)); - 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; - *val = ret; + 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"); -static int ds4424_set_value(struct iio_dev *indio_dev, - int val, struct iio_chan_spec const *chan) -{ - struct ds4424_data *data = iio_priv(indio_dev); - 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; - - data->raw[chan->channel] = val; - -fail: - mutex_unlock(&data->lock); - return ret; + return 0; } static int ds4424_read_raw(struct iio_dev *indio_dev, @@ -123,11 +154,13 @@ 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", @@ -170,58 +203,44 @@ static int ds4424_write_raw(struct iio_dev *indio_dev, 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; + u8 zero_buf[DS4424_MAX_DAC_CHANNELS] = { }; + int ret; - 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; + /* 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); @@ -248,7 +267,6 @@ static int ds4424_probe(struct i2c_client *client) 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; @@ -257,7 +275,6 @@ static int ds4424_probe(struct i2c_client *client) 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, @@ -272,15 +289,15 @@ static int ds4424_probe(struct i2c_client *client) */ 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,