Merge tag 'staging-4.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
Pull staging and IIO updates from Greg KH: "Here is the "big" staging and IIO driver update for 4.15-rc1. Lots and lots of little changes, almost all minor code cleanups as the Outreachy application process happened during this development cycle. Also happened was a lot of IIO driver activity, and the typec USB code moving out of staging to drivers/usb (same commits are in the USB tree on a persistent branch to not cause merge issues.) Overall, it's a wash, I think we added a few hundred more lines than removed, but really only a few thousand were modified at all. All of these have been in linux-next for a while. There might be a merge issue with Al's vfs tree in the pi433 driver (take his changes, they are always better), and the media tree with some of the odd atomisp cleanups (take the media tree's version)" * tag 'staging-4.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (507 commits) staging: lustre: add SPDX identifiers to all lustre files staging: greybus: Remove redundant license text staging: greybus: add SPDX identifiers to all greybus driver files staging: ccree: simplify ioread/iowrite staging: ccree: simplify registers access staging: ccree: simplify error handling logic staging: ccree: remove dead code staging: ccree: handle limiting of DMA masks staging: ccree: copy IV to DMAable memory staging: fbtft: remove redundant initialization of buf staging: sm750fb: Fix parameter mistake in poke32 staging: wilc1000: Fix bssid buffer offset in Txq staging: fbtft: fb_ssd1331: fix mirrored display staging: android: Fix checkpatch.pl error staging: greybus: loopback: convert loopback to use generic async operations staging: greybus: operation: add private data with get/set accessors staging: greybus: loopback: Fix iteration count on async path staging: greybus: loopback: Hold per-connection mutex across operations staging: greybus/loopback: use ktime_get() for time intervals staging: fsl-dpaa2/eth: Extra headroom in RX buffers ...
This commit is contained in:
@@ -60,7 +60,8 @@ config AD5446
|
||||
Say yes here to build support for Analog Devices AD5300, AD5301, AD5310,
|
||||
AD5311, AD5320, AD5321, AD5444, AD5446, AD5450, AD5451, AD5452, AD5453,
|
||||
AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601, AD5602, AD5611, AD5612,
|
||||
AD5620, AD5621, AD5622, AD5640, AD5641, AD5660, AD5662 DACs.
|
||||
AD5620, AD5621, AD5622, AD5640, AD5641, AD5660, AD5662 DACs
|
||||
as well as Texas Instruments DAC081S101, DAC101S101, DAC121S101.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ad5446.
|
||||
@@ -221,6 +222,15 @@ config DPOT_DAC
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called dpot-dac.
|
||||
|
||||
config DS4424
|
||||
tristate "Maxim Integrated DS4422/DS4424 DAC driver"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for Maxim chips DS4422, DS4424.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called ds4424.
|
||||
|
||||
config LPC18XX_DAC
|
||||
tristate "NXP LPC18xx DAC driver"
|
||||
depends on ARCH_LPC18XX || COMPILE_TEST
|
||||
@@ -300,6 +310,16 @@ config STM32_DAC
|
||||
config STM32_DAC_CORE
|
||||
tristate
|
||||
|
||||
config TI_DAC082S085
|
||||
tristate "Texas Instruments 8/10/12-bit 2/4-channel DAC driver"
|
||||
depends on SPI_MASTER
|
||||
help
|
||||
Driver for the Texas Instruments (formerly National Semiconductor)
|
||||
DAC082S085, DAC102S085, DAC122S085, DAC084S085, DAC104S085 and
|
||||
DAC124S085.
|
||||
|
||||
If compiled as a module, it will be called ti-dac082s085.
|
||||
|
||||
config VF610_DAC
|
||||
tristate "Vybrid vf610 DAC driver"
|
||||
depends on OF
|
||||
|
@@ -24,6 +24,7 @@ obj-$(CONFIG_AD7303) += ad7303.o
|
||||
obj-$(CONFIG_AD8801) += ad8801.o
|
||||
obj-$(CONFIG_CIO_DAC) += cio-dac.o
|
||||
obj-$(CONFIG_DPOT_DAC) += dpot-dac.o
|
||||
obj-$(CONFIG_DS4424) += ds4424.o
|
||||
obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o
|
||||
obj-$(CONFIG_LTC2632) += ltc2632.o
|
||||
obj-$(CONFIG_M62332) += m62332.o
|
||||
@@ -33,4 +34,5 @@ obj-$(CONFIG_MCP4725) += mcp4725.o
|
||||
obj-$(CONFIG_MCP4922) += mcp4922.o
|
||||
obj-$(CONFIG_STM32_DAC_CORE) += stm32-dac-core.o
|
||||
obj-$(CONFIG_STM32_DAC) += stm32-dac.o
|
||||
obj-$(CONFIG_TI_DAC082S085) += ti-dac082s085.o
|
||||
obj-$(CONFIG_VF610_DAC) += vf610_dac.o
|
||||
|
@@ -366,7 +366,6 @@ static int ad5064_write_raw(struct iio_dev *indio_dev,
|
||||
static const struct iio_info ad5064_info = {
|
||||
.read_raw = ad5064_read_raw,
|
||||
.write_raw = ad5064_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec_ext_info ad5064_ext_info[] = {
|
||||
|
@@ -425,7 +425,6 @@ static const struct iio_info ad5360_info = {
|
||||
.read_raw = ad5360_read_raw,
|
||||
.write_raw = ad5360_write_raw,
|
||||
.attrs = &ad5360_attribute_group,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const char * const ad5360_vref_name[] = {
|
||||
|
@@ -237,7 +237,6 @@ static int ad5380_read_raw(struct iio_dev *indio_dev,
|
||||
static const struct iio_info ad5380_info = {
|
||||
.read_raw = ad5380_read_raw,
|
||||
.write_raw = ad5380_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static struct iio_chan_spec_ext_info ad5380_ext_info[] = {
|
||||
|
@@ -465,7 +465,6 @@ static const struct iio_info ad5421_info = {
|
||||
.read_event_config = ad5421_read_event_config,
|
||||
.write_event_config = ad5421_write_event_config,
|
||||
.read_event_value = ad5421_read_event_value,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int ad5421_probe(struct spi_device *spi)
|
||||
|
@@ -212,7 +212,6 @@ static int ad5446_write_raw(struct iio_dev *indio_dev,
|
||||
static const struct iio_info ad5446_info = {
|
||||
.read_raw = ad5446_read_raw,
|
||||
.write_raw = ad5446_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int ad5446_probe(struct device *dev, const char *name,
|
||||
@@ -461,10 +460,22 @@ static const struct spi_device_id ad5446_spi_ids[] = {
|
||||
{"ad5660-2500", ID_AD5660_2500},
|
||||
{"ad5660-1250", ID_AD5660_1250},
|
||||
{"ad5662", ID_AD5662},
|
||||
{"dac081s101", ID_AD5300}, /* compatible Texas Instruments chips */
|
||||
{"dac101s101", ID_AD5310},
|
||||
{"dac121s101", ID_AD5320},
|
||||
{"dac7512", ID_AD5320},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad5446_spi_ids);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id ad5446_of_ids[] = {
|
||||
{ .compatible = "ti,dac7512" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad5446_of_ids);
|
||||
#endif
|
||||
|
||||
static int ad5446_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
@@ -481,6 +492,7 @@ static int ad5446_spi_remove(struct spi_device *spi)
|
||||
static struct spi_driver ad5446_spi_driver = {
|
||||
.driver = {
|
||||
.name = "ad5446",
|
||||
.of_match_table = of_match_ptr(ad5446_of_ids),
|
||||
},
|
||||
.probe = ad5446_spi_probe,
|
||||
.remove = ad5446_spi_remove,
|
||||
|
@@ -193,7 +193,6 @@ static int ad5449_write_raw(struct iio_dev *indio_dev,
|
||||
static const struct iio_info ad5449_info = {
|
||||
.read_raw = ad5449_read_raw,
|
||||
.write_raw = ad5449_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
#define AD5449_CHANNEL(chan, bits) { \
|
||||
|
@@ -232,7 +232,6 @@ static const struct iio_info ad5504_info = {
|
||||
.write_raw = ad5504_write_raw,
|
||||
.read_raw = ad5504_read_raw,
|
||||
.event_attrs = &ad5504_ev_attribute_group,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec_ext_info ad5504_ext_info[] = {
|
||||
|
@@ -474,7 +474,6 @@ static const struct iio_info ad5592r_info = {
|
||||
.read_raw = ad5592r_read_raw,
|
||||
.write_raw = ad5592r_write_raw,
|
||||
.write_raw_get_fmt = ad5592r_write_raw_get_fmt,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static ssize_t ad5592r_show_scale_available(struct iio_dev *iio_dev,
|
||||
|
@@ -149,7 +149,6 @@ static ssize_t ad5624r_write_dac_powerdown(struct iio_dev *indio_dev,
|
||||
static const struct iio_info ad5624r_info = {
|
||||
.write_raw = ad5624r_write_raw,
|
||||
.read_raw = ad5624r_read_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec_ext_info ad5624r_ext_info[] = {
|
||||
|
@@ -252,7 +252,6 @@ static int ad5686_write_raw(struct iio_dev *indio_dev,
|
||||
static const struct iio_info ad5686_info = {
|
||||
.read_raw = ad5686_read_raw,
|
||||
.write_raw = ad5686_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec_ext_info ad5686_ext_info[] = {
|
||||
|
@@ -417,7 +417,6 @@ static ssize_t ad5755_write_powerdown(struct iio_dev *indio_dev, uintptr_t priv,
|
||||
static const struct iio_info ad5755_info = {
|
||||
.read_raw = ad5755_read_raw,
|
||||
.write_raw = ad5755_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec_ext_info ad5755_ext_info[] = {
|
||||
|
@@ -251,7 +251,6 @@ static int ad5761_write_raw(struct iio_dev *indio_dev,
|
||||
static const struct iio_info ad5761_info = {
|
||||
.read_raw = &ad5761_read_raw,
|
||||
.write_raw = &ad5761_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
#define AD5761_CHAN(_bits) { \
|
||||
|
@@ -268,7 +268,6 @@ static int ad5764_read_raw(struct iio_dev *indio_dev,
|
||||
static const struct iio_info ad5764_info = {
|
||||
.read_raw = ad5764_read_raw,
|
||||
.write_raw = ad5764_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int ad5764_probe(struct spi_device *spi)
|
||||
|
@@ -340,7 +340,6 @@ static int ad5791_write_raw(struct iio_dev *indio_dev,
|
||||
static const struct iio_info ad5791_info = {
|
||||
.read_raw = &ad5791_read_raw,
|
||||
.write_raw = &ad5791_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int ad5791_probe(struct spi_device *spi)
|
||||
|
@@ -161,7 +161,6 @@ static int ad7303_write_raw(struct iio_dev *indio_dev,
|
||||
static const struct iio_info ad7303_info = {
|
||||
.read_raw = ad7303_read_raw,
|
||||
.write_raw = ad7303_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec_ext_info ad7303_ext_info[] = {
|
||||
|
@@ -92,7 +92,6 @@ static int ad8801_read_raw(struct iio_dev *indio_dev,
|
||||
static const struct iio_info ad8801_info = {
|
||||
.read_raw = ad8801_read_raw,
|
||||
.write_raw = ad8801_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
#define AD8801_CHANNEL(chan) { \
|
||||
|
@@ -85,7 +85,6 @@ static int cio_dac_write_raw(struct iio_dev *indio_dev,
|
||||
}
|
||||
|
||||
static const struct iio_info cio_dac_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.read_raw = cio_dac_read_raw,
|
||||
.write_raw = cio_dac_write_raw
|
||||
};
|
||||
|
@@ -128,7 +128,6 @@ static const struct iio_info dpot_dac_info = {
|
||||
.read_raw = dpot_dac_read_raw,
|
||||
.read_avail = dpot_dac_read_avail,
|
||||
.write_raw = dpot_dac_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int dpot_dac_channel_max_ohms(struct iio_dev *indio_dev)
|
||||
|
341
drivers/iio/dac/ds4424.c
Normal file
341
drivers/iio/dac/ds4424.c
Normal file
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Maxim Integrated
|
||||
* 7-bit, Multi-Channel Sink/Source Current DAC Driver
|
||||
* Copyright (C) 2017 Maxim Integrated
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/driver.h>
|
||||
#include <linux/iio/machine.h>
|
||||
#include <linux/iio/consumer.h>
|
||||
|
||||
#define DS4422_MAX_DAC_CHANNELS 2
|
||||
#define DS4424_MAX_DAC_CHANNELS 4
|
||||
|
||||
#define DS4424_DAC_ADDR(chan) ((chan) + 0xf8)
|
||||
#define DS4424_SOURCE_I 1
|
||||
#define DS4424_SINK_I 0
|
||||
|
||||
#define DS4424_CHANNEL(chan) { \
|
||||
.type = IIO_CURRENT, \
|
||||
.indexed = 1, \
|
||||
.output = 1, \
|
||||
.channel = chan, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
}
|
||||
|
||||
/*
|
||||
* DS4424 DAC control register 8 bits
|
||||
* [7] 0: to sink; 1: to source
|
||||
* [6:0] steps to sink/source
|
||||
* bit[7] looks like a sign bit, but the value of the register is
|
||||
* not a two's complement code considering the bit[6:0] is a absolute
|
||||
* distance from the zero point.
|
||||
*/
|
||||
union ds4424_raw_data {
|
||||
struct {
|
||||
u8 dx:7;
|
||||
u8 source_bit:1;
|
||||
};
|
||||
u8 bits;
|
||||
};
|
||||
|
||||
enum ds4424_device_ids {
|
||||
ID_DS4422,
|
||||
ID_DS4424,
|
||||
};
|
||||
|
||||
struct ds4424_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
uint8_t save[DS4424_MAX_DAC_CHANNELS];
|
||||
struct regulator *vcc_reg;
|
||||
uint8_t raw[DS4424_MAX_DAC_CHANNELS];
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ds4424_channels[] = {
|
||||
DS4424_CHANNEL(0),
|
||||
DS4424_CHANNEL(1),
|
||||
DS4424_CHANNEL(2),
|
||||
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;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
ret = i2c_smbus_read_byte_data(data->client, DS4424_DAC_ADDR(channel));
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
*val = ret;
|
||||
|
||||
fail:
|
||||
mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int ds4424_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
union ds4424_raw_data raw;
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
ret = ds4424_get_value(indio_dev, val, chan->channel);
|
||||
if (ret < 0) {
|
||||
pr_err("%s : ds4424_get_value returned %d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
raw.bits = *val;
|
||||
*val = raw.dx;
|
||||
if (raw.source_bit == DS4424_SINK_I)
|
||||
*val = -*val;
|
||||
return IIO_VAL_INT;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ds4424_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
union ds4424_raw_data raw;
|
||||
|
||||
if (val2 != 0)
|
||||
return -EINVAL;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (val < S8_MIN || val > S8_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (val > 0) {
|
||||
raw.source_bit = DS4424_SOURCE_I;
|
||||
raw.dx = val;
|
||||
} else {
|
||||
raw.source_bit = DS4424_SINK_I;
|
||||
raw.dx = -val;
|
||||
}
|
||||
|
||||
return ds4424_set_value(indio_dev, raw.bits, chan);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ds4424_verify_chip(struct iio_dev *indio_dev)
|
||||
{
|
||||
int ret, val;
|
||||
|
||||
ret = ds4424_get_value(indio_dev, &val, DS4424_DAC_ADDR(0));
|
||||
if (ret < 0)
|
||||
dev_err(&indio_dev->dev,
|
||||
"%s failed. ret: %d\n", __func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused ds4424_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
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;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused ds4424_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
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;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(ds4424_pm_ops, ds4424_suspend, ds4424_resume);
|
||||
|
||||
static const struct iio_info ds4424_info = {
|
||||
.read_raw = ds4424_read_raw,
|
||||
.write_raw = ds4424_write_raw,
|
||||
};
|
||||
|
||||
static int ds4424_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct ds4424_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev) {
|
||||
dev_err(&client->dev, "iio dev alloc failed.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->dev.of_node = client->dev.of_node;
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
|
||||
if (!client->dev.of_node) {
|
||||
dev_err(&client->dev,
|
||||
"Not found DT.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
data->vcc_reg = devm_regulator_get(&client->dev, "vcc");
|
||||
if (IS_ERR(data->vcc_reg)) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to get vcc-supply regulator. err: %ld\n",
|
||||
PTR_ERR(data->vcc_reg));
|
||||
return PTR_ERR(data->vcc_reg);
|
||||
}
|
||||
|
||||
mutex_init(&data->lock);
|
||||
ret = regulator_enable(data->vcc_reg);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev,
|
||||
"Unable to enable the regulator.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
usleep_range(1000, 1200);
|
||||
ret = ds4424_verify_chip(indio_dev);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
switch (id->driver_data) {
|
||||
case ID_DS4422:
|
||||
indio_dev->num_channels = DS4422_MAX_DAC_CHANNELS;
|
||||
break;
|
||||
case ID_DS4424:
|
||||
indio_dev->num_channels = DS4424_MAX_DAC_CHANNELS;
|
||||
break;
|
||||
default:
|
||||
dev_err(&client->dev,
|
||||
"ds4424: Invalid chip id.\n");
|
||||
ret = -ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
indio_dev->channels = ds4424_channels;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &ds4424_info;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev,
|
||||
"iio_device_register failed. ret: %d\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
regulator_disable(data->vcc_reg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ds4424_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
struct ds4424_data *data = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
regulator_disable(data->vcc_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ds4424_id[] = {
|
||||
{ "ds4422", ID_DS4422 },
|
||||
{ "ds4424", ID_DS4424 },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, ds4424_id);
|
||||
|
||||
static const struct of_device_id ds4424_of_match[] = {
|
||||
{ .compatible = "maxim,ds4422" },
|
||||
{ .compatible = "maxim,ds4424" },
|
||||
{ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, ds4424_of_match);
|
||||
|
||||
static struct i2c_driver ds4424_driver = {
|
||||
.driver = {
|
||||
.name = "ds4424",
|
||||
.of_match_table = ds4424_of_match,
|
||||
.pm = &ds4424_pm_ops,
|
||||
},
|
||||
.probe = ds4424_probe,
|
||||
.remove = ds4424_remove,
|
||||
.id_table = ds4424_id,
|
||||
};
|
||||
module_i2c_driver(ds4424_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Maxim DS4424 DAC Driver");
|
||||
MODULE_AUTHOR("Ismail H. Kose <ismail.kose@maximintegrated.com>");
|
||||
MODULE_AUTHOR("Vishal Sood <vishal.sood@maximintegrated.com>");
|
||||
MODULE_AUTHOR("David Jung <david.jung@maximintegrated.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
@@ -103,7 +103,6 @@ static int lpc18xx_dac_write_raw(struct iio_dev *indio_dev,
|
||||
static const struct iio_info lpc18xx_dac_info = {
|
||||
.read_raw = lpc18xx_dac_read_raw,
|
||||
.write_raw = lpc18xx_dac_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int lpc18xx_dac_probe(struct platform_device *pdev)
|
||||
|
@@ -159,7 +159,6 @@ static ssize_t ltc2632_write_dac_powerdown(struct iio_dev *indio_dev,
|
||||
static const struct iio_info ltc2632_info = {
|
||||
.write_raw = ltc2632_write_raw,
|
||||
.read_raw = ltc2632_read_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec_ext_info ltc2632_ext_info[] = {
|
||||
|
@@ -174,7 +174,6 @@ static SIMPLE_DEV_PM_OPS(m62332_pm_ops, m62332_suspend, m62332_resume);
|
||||
static const struct iio_info m62332_info = {
|
||||
.read_raw = m62332_read_raw,
|
||||
.write_raw = m62332_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
#define M62332_CHANNEL(chan) { \
|
||||
|
@@ -137,7 +137,6 @@ static SIMPLE_DEV_PM_OPS(max517_pm_ops, max517_suspend, max517_resume);
|
||||
static const struct iio_info max517_info = {
|
||||
.read_raw = max517_read_raw,
|
||||
.write_raw = max517_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
#define MAX517_CHANNEL(chan) { \
|
||||
|
@@ -300,7 +300,6 @@ static SIMPLE_DEV_PM_OPS(max5821_pm_ops, max5821_suspend, max5821_resume);
|
||||
static const struct iio_info max5821_info = {
|
||||
.read_raw = max5821_read_raw,
|
||||
.write_raw = max5821_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int max5821_probe(struct i2c_client *client,
|
||||
|
@@ -363,7 +363,6 @@ static const struct iio_info mcp4725_info = {
|
||||
.read_raw = mcp4725_read_raw,
|
||||
.write_raw = mcp4725_write_raw,
|
||||
.attrs = &mcp4725_attribute_group,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
@@ -119,7 +119,6 @@ static const struct iio_chan_spec mcp4922_channels[3][MCP4922_NUM_CHANNELS] = {
|
||||
static const struct iio_info mcp4922_info = {
|
||||
.read_raw = &mcp4922_read_raw,
|
||||
.write_raw = &mcp4922_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int mcp4922_probe(struct spi_device *spi)
|
||||
|
@@ -156,7 +156,6 @@ static const struct iio_info stm32_dac_iio_info = {
|
||||
.read_raw = stm32_dac_read_raw,
|
||||
.write_raw = stm32_dac_write_raw,
|
||||
.debugfs_reg_access = stm32_dac_debugfs_reg_access,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const char * const stm32_dac_powerdown_modes[] = {
|
||||
|
368
drivers/iio/dac/ti-dac082s085.c
Normal file
368
drivers/iio/dac/ti-dac082s085.c
Normal file
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* ti-dac082s085.c - Texas Instruments 8/10/12-bit 2/4-channel DAC driver
|
||||
*
|
||||
* Copyright (C) 2017 KUNBUS GmbH
|
||||
*
|
||||
* http://www.ti.com/lit/ds/symlink/dac082s085.pdf
|
||||
* http://www.ti.com/lit/ds/symlink/dac102s085.pdf
|
||||
* http://www.ti.com/lit/ds/symlink/dac122s085.pdf
|
||||
* http://www.ti.com/lit/ds/symlink/dac084s085.pdf
|
||||
* http://www.ti.com/lit/ds/symlink/dac104s085.pdf
|
||||
* http://www.ti.com/lit/ds/symlink/dac124s085.pdf
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License (version 2) as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
enum { dual_8bit, dual_10bit, dual_12bit, quad_8bit, quad_10bit, quad_12bit };
|
||||
|
||||
struct ti_dac_spec {
|
||||
u8 num_channels;
|
||||
u8 resolution;
|
||||
};
|
||||
|
||||
static const struct ti_dac_spec ti_dac_spec[] = {
|
||||
[dual_8bit] = { .num_channels = 2, .resolution = 8 },
|
||||
[dual_10bit] = { .num_channels = 2, .resolution = 10 },
|
||||
[dual_12bit] = { .num_channels = 2, .resolution = 12 },
|
||||
[quad_8bit] = { .num_channels = 4, .resolution = 8 },
|
||||
[quad_10bit] = { .num_channels = 4, .resolution = 10 },
|
||||
[quad_12bit] = { .num_channels = 4, .resolution = 12 },
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ti_dac_chip - TI DAC chip
|
||||
* @lock: protects write sequences
|
||||
* @vref: regulator generating Vref
|
||||
* @mesg: SPI message to perform a write
|
||||
* @xfer: SPI transfer used by @mesg
|
||||
* @val: cached value of each output
|
||||
* @powerdown: whether the chip is powered down
|
||||
* @powerdown_mode: selected by the user
|
||||
* @resolution: resolution of the chip
|
||||
* @buf: buffer for @xfer
|
||||
*/
|
||||
struct ti_dac_chip {
|
||||
struct mutex lock;
|
||||
struct regulator *vref;
|
||||
struct spi_message mesg;
|
||||
struct spi_transfer xfer;
|
||||
u16 val[4];
|
||||
bool powerdown;
|
||||
u8 powerdown_mode;
|
||||
u8 resolution;
|
||||
u8 buf[2] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
#define WRITE_NOT_UPDATE(chan) (0x00 | (chan) << 6)
|
||||
#define WRITE_AND_UPDATE(chan) (0x10 | (chan) << 6)
|
||||
#define WRITE_ALL_UPDATE 0x20
|
||||
#define POWERDOWN(mode) (0x30 | ((mode) + 1) << 6)
|
||||
|
||||
static int ti_dac_cmd(struct ti_dac_chip *ti_dac, u8 cmd, u16 val)
|
||||
{
|
||||
u8 shift = 12 - ti_dac->resolution;
|
||||
|
||||
ti_dac->buf[0] = cmd | (val >> (8 - shift));
|
||||
ti_dac->buf[1] = (val << shift) & 0xff;
|
||||
return spi_sync(ti_dac->mesg.spi, &ti_dac->mesg);
|
||||
}
|
||||
|
||||
static const char * const ti_dac_powerdown_modes[] = {
|
||||
"2.5kohm_to_gnd", "100kohm_to_gnd", "three_state",
|
||||
};
|
||||
|
||||
static int ti_dac_get_powerdown_mode(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
|
||||
|
||||
return ti_dac->powerdown_mode;
|
||||
}
|
||||
|
||||
static int ti_dac_set_powerdown_mode(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
unsigned int mode)
|
||||
{
|
||||
struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
|
||||
int ret = 0;
|
||||
|
||||
if (ti_dac->powerdown_mode == mode)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&ti_dac->lock);
|
||||
if (ti_dac->powerdown) {
|
||||
ret = ti_dac_cmd(ti_dac, POWERDOWN(mode), 0);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
ti_dac->powerdown_mode = mode;
|
||||
|
||||
out:
|
||||
mutex_unlock(&ti_dac->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct iio_enum ti_dac_powerdown_mode = {
|
||||
.items = ti_dac_powerdown_modes,
|
||||
.num_items = ARRAY_SIZE(ti_dac_powerdown_modes),
|
||||
.get = ti_dac_get_powerdown_mode,
|
||||
.set = ti_dac_set_powerdown_mode,
|
||||
};
|
||||
|
||||
static ssize_t ti_dac_read_powerdown(struct iio_dev *indio_dev,
|
||||
uintptr_t private,
|
||||
const struct iio_chan_spec *chan,
|
||||
char *buf)
|
||||
{
|
||||
struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
|
||||
|
||||
return sprintf(buf, "%d\n", ti_dac->powerdown);
|
||||
}
|
||||
|
||||
static ssize_t ti_dac_write_powerdown(struct iio_dev *indio_dev,
|
||||
uintptr_t private,
|
||||
const struct iio_chan_spec *chan,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
|
||||
bool powerdown;
|
||||
int ret;
|
||||
|
||||
ret = strtobool(buf, &powerdown);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ti_dac->powerdown == powerdown)
|
||||
return len;
|
||||
|
||||
mutex_lock(&ti_dac->lock);
|
||||
if (powerdown)
|
||||
ret = ti_dac_cmd(ti_dac, POWERDOWN(ti_dac->powerdown_mode), 0);
|
||||
else
|
||||
ret = ti_dac_cmd(ti_dac, WRITE_AND_UPDATE(0), ti_dac->val[0]);
|
||||
if (!ret)
|
||||
ti_dac->powerdown = powerdown;
|
||||
mutex_unlock(&ti_dac->lock);
|
||||
|
||||
return ret ? ret : len;
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec_ext_info ti_dac_ext_info[] = {
|
||||
{
|
||||
.name = "powerdown",
|
||||
.read = ti_dac_read_powerdown,
|
||||
.write = ti_dac_write_powerdown,
|
||||
.shared = IIO_SHARED_BY_TYPE,
|
||||
},
|
||||
IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, &ti_dac_powerdown_mode),
|
||||
IIO_ENUM_AVAILABLE("powerdown_mode", &ti_dac_powerdown_mode),
|
||||
{ },
|
||||
};
|
||||
|
||||
#define TI_DAC_CHANNEL(chan) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.channel = (chan), \
|
||||
.address = (chan), \
|
||||
.indexed = true, \
|
||||
.output = true, \
|
||||
.datasheet_name = (const char[]){ 'A' + (chan), 0 }, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.ext_info = ti_dac_ext_info, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec ti_dac_channels[] = {
|
||||
TI_DAC_CHANNEL(0),
|
||||
TI_DAC_CHANNEL(1),
|
||||
TI_DAC_CHANNEL(2),
|
||||
TI_DAC_CHANNEL(3),
|
||||
};
|
||||
|
||||
static int ti_dac_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
*val = ti_dac->val[chan->channel];
|
||||
ret = IIO_VAL_INT;
|
||||
break;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
ret = regulator_get_voltage(ti_dac->vref);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = ret / 1000;
|
||||
*val2 = ti_dac->resolution;
|
||||
ret = IIO_VAL_FRACTIONAL_LOG2;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ti_dac_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (ti_dac->val[chan->channel] == val)
|
||||
return 0;
|
||||
|
||||
if (val >= (1 << ti_dac->resolution) || val < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (ti_dac->powerdown)
|
||||
return -EBUSY;
|
||||
|
||||
mutex_lock(&ti_dac->lock);
|
||||
ret = ti_dac_cmd(ti_dac, WRITE_AND_UPDATE(chan->channel), val);
|
||||
if (!ret)
|
||||
ti_dac->val[chan->channel] = val;
|
||||
mutex_unlock(&ti_dac->lock);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ti_dac_write_raw_get_fmt(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, long mask)
|
||||
{
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static const struct iio_info ti_dac_info = {
|
||||
.read_raw = ti_dac_read_raw,
|
||||
.write_raw = ti_dac_write_raw,
|
||||
.write_raw_get_fmt = ti_dac_write_raw_get_fmt,
|
||||
};
|
||||
|
||||
static int ti_dac_probe(struct spi_device *spi)
|
||||
{
|
||||
struct device *dev = &spi->dev;
|
||||
const struct ti_dac_spec *spec;
|
||||
struct ti_dac_chip *ti_dac;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*ti_dac));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
indio_dev->dev.parent = dev;
|
||||
indio_dev->info = &ti_dac_info;
|
||||
indio_dev->name = spi->modalias;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = ti_dac_channels;
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
ti_dac = iio_priv(indio_dev);
|
||||
ti_dac->xfer.tx_buf = &ti_dac->buf;
|
||||
ti_dac->xfer.len = sizeof(ti_dac->buf);
|
||||
spi_message_init_with_transfers(&ti_dac->mesg, &ti_dac->xfer, 1);
|
||||
ti_dac->mesg.spi = spi;
|
||||
|
||||
spec = &ti_dac_spec[spi_get_device_id(spi)->driver_data];
|
||||
indio_dev->num_channels = spec->num_channels;
|
||||
ti_dac->resolution = spec->resolution;
|
||||
|
||||
ti_dac->vref = devm_regulator_get(dev, "vref");
|
||||
if (IS_ERR(ti_dac->vref))
|
||||
return PTR_ERR(ti_dac->vref);
|
||||
|
||||
ret = regulator_enable(ti_dac->vref);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mutex_init(&ti_dac->lock);
|
||||
|
||||
ret = ti_dac_cmd(ti_dac, WRITE_ALL_UPDATE, 0);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize outputs to 0\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
mutex_destroy(&ti_dac->lock);
|
||||
regulator_disable(ti_dac->vref);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ti_dac_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
mutex_destroy(&ti_dac->lock);
|
||||
regulator_disable(ti_dac->vref);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id ti_dac_of_id[] = {
|
||||
{ .compatible = "ti,dac082s085" },
|
||||
{ .compatible = "ti,dac102s085" },
|
||||
{ .compatible = "ti,dac122s085" },
|
||||
{ .compatible = "ti,dac084s085" },
|
||||
{ .compatible = "ti,dac104s085" },
|
||||
{ .compatible = "ti,dac124s085" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ti_dac_of_id);
|
||||
#endif
|
||||
|
||||
static const struct spi_device_id ti_dac_spi_id[] = {
|
||||
{ "dac082s085", dual_8bit },
|
||||
{ "dac102s085", dual_10bit },
|
||||
{ "dac122s085", dual_12bit },
|
||||
{ "dac084s085", quad_8bit },
|
||||
{ "dac104s085", quad_10bit },
|
||||
{ "dac124s085", quad_12bit },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ti_dac_spi_id);
|
||||
|
||||
static struct spi_driver ti_dac_driver = {
|
||||
.driver = {
|
||||
.name = "ti-dac082s085",
|
||||
.of_match_table = of_match_ptr(ti_dac_of_id),
|
||||
},
|
||||
.probe = ti_dac_probe,
|
||||
.remove = ti_dac_remove,
|
||||
.id_table = ti_dac_spi_id,
|
||||
};
|
||||
module_spi_driver(ti_dac_driver);
|
||||
|
||||
MODULE_AUTHOR("Lukas Wunner <lukas@wunner.de>");
|
||||
MODULE_DESCRIPTION("Texas Instruments 8/10/12-bit 2/4-channel DAC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@@ -167,7 +167,6 @@ static int vf610_write_raw(struct iio_dev *indio_dev,
|
||||
}
|
||||
|
||||
static const struct iio_info vf610_dac_iio_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.read_raw = &vf610_read_raw,
|
||||
.write_raw = &vf610_write_raw,
|
||||
};
|
||||
|
Reference in New Issue
Block a user