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:
Linus Torvalds
2017-11-13 20:53:28 -08:00
1008 changed files with 8575 additions and 8394 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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[] = {

View File

@@ -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[] = {

View File

@@ -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[] = {

View File

@@ -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)

View File

@@ -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,

View File

@@ -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) { \

View File

@@ -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[] = {

View File

@@ -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,

View File

@@ -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[] = {

View File

@@ -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[] = {

View File

@@ -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[] = {

View File

@@ -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) { \

View File

@@ -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)

View File

@@ -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)

View File

@@ -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[] = {

View File

@@ -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) { \

View File

@@ -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
};

View File

@@ -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
View 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");

View File

@@ -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)

View File

@@ -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[] = {

View File

@@ -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) { \

View File

@@ -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) { \

View File

@@ -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,

View File

@@ -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

View File

@@ -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)

View File

@@ -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[] = {

View 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");

View File

@@ -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,
};