Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1231384 > unrolled thread
| Started by | Peter Rosin <peda@lysator.liu.se> |
|---|---|
| First post | 2015-09-23 14:00 +0200 |
| Last post | 2015-09-23 14:00 +0200 |
| Articles | 4 — 2 participants |
Back to article view | Back to linux.kernel
[PATCH v5 0/2] Driver for Microchip digital potentiometers Peter Rosin <peda@lysator.liu.se> - 2015-09-23 14:00 +0200
[PATCH v5 2/2] iio: mcp4531: Driver for Microchip digital potentiometers Peter Rosin <peda@lysator.liu.se> - 2015-09-23 14:00 +0200
Re: [PATCH v5 2/2] iio: mcp4531: Driver for Microchip digital potentiometers Lars-Peter Clausen <lars@metafoo.de> - 2015-09-23 15:30 +0200
[PATCH v5 1/2] iio: resistance: Document that resistance can be output Peter Rosin <peda@lysator.liu.se> - 2015-09-23 14:00 +0200
| From | Peter Rosin <peda@lysator.liu.se> |
|---|---|
| Date | 2015-09-23 14:00 +0200 |
| Subject | [PATCH v5 0/2] Driver for Microchip digital potentiometers |
| Message-ID | <qbQSl-3fk-1@gated-at.bofh.it> |
From: Peter Rosin <peda@axentia.se> This is the fifth attempt for a driver for these chips. Thanks for review comments from Greg Kroah-Hartman, Crt Mori, Daniel Baluta, Lars-Peter Clauson, Andreas Dannenberg, Peter Meerwald and Jonathan Cameron. I think and hope I got it all sorted. Changes since v4: - Less convoluted changelog (Jonathan) - Use an index into an array of configs as dev_id (Jonathan) - Drop .address and use .channel (Jonathan) - Remove one layer of wrappers (Jonathan) - Provide a scale (Jonathan, Lars-Peter) Changes since v3: - Use i2c_smbus_read_word_swapped (Peter) - Use devm_iio_device_register and drop the mcp4531_remove op (Peter) - Add defines for a few magic numbers (Peter) - Deduplicate channel params with a macro (Peter) - Mention the i2c client address options (Peter) - Whitespace and other trivial nits (Peter) Changes since v2: - Change naming from mcp4xxx_dpot to mcp4531 (Daniel) - Added links to datasheet in commit message and source (Daniel) - Rename from pot to potentiometer (Daniel, Crt) - Use IIO_RESISTANCE instead of IIO_STEPS (Crt, Lars-Peter) - Don't use wildcards in MAINTAINERS and point to the iio list (Crt) - Avoid races by not caching values (Crt) - Spell Microchip correctly (Andreas) Changes since v1: - Make it an IIO driver instead (Greg) - Don't convolute the code with big obscure macros (Greg) - Inline the bits from mcp4xxx_dpot.h that are actually used and drop that file (me) - Better Changelog (Greg) Cheers, Peter Peter Rosin (2): iio: resistance: Document that resistance can be output iio: mcp4531: Driver for Microchip digital potentiometers Documentation/ABI/testing/sysfs-bus-iio | 2 + MAINTAINERS | 6 + drivers/iio/Kconfig | 1 + drivers/iio/Makefile | 1 + drivers/iio/potentiometer/Kconfig | 20 +++ drivers/iio/potentiometer/Makefile | 6 + drivers/iio/potentiometer/mcp4531.c | 228 +++++++++++++++++++++++++++++++ 7 files changed, 264 insertions(+) create mode 100644 drivers/iio/potentiometer/Kconfig create mode 100644 drivers/iio/potentiometer/Makefile create mode 100644 drivers/iio/potentiometer/mcp4531.c -- 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [next] | [standalone]
| From | Peter Rosin <peda@lysator.liu.se> |
|---|---|
| Date | 2015-09-23 14:00 +0200 |
| Subject | [PATCH v5 2/2] iio: mcp4531: Driver for Microchip digital potentiometers |
| Message-ID | <qbQSm-3fk-11@gated-at.bofh.it> |
| In reply to | #1231384 |
From: Peter Rosin <peda@axentia.se>
Add support for Microchip digital potentiometers and rheostats
MCP4531, MCP4532, MCP4551, MCP4552
MCP4631, MCP4632, MCP4651, MCP4652
DEVICE Wipers Steps Resistor Opts (kOhm) i2c address
MCP4531 1 129 5, 10, 50, 100 010111x
MCP4532 1 129 5, 10, 50, 100 01011xx
MCP4551 1 257 5, 10, 50, 100 010111x
MCP4552 1 257 5, 10, 50, 100 01011xx
MCP4631 2 129 5, 10, 50, 100 0101xxx
MCP4632 2 129 5, 10, 50, 100 01011xx
MCP4651 2 257 5, 10, 50, 100 0101xxx
MCP4652 2 257 5, 10, 50, 100 01011xx
Datasheet: http://www.microchip.com/downloads/en/DeviceDoc/22096b.pdf
Signed-off-by: Peter Rosin <peda@axentia.se>
---
MAINTAINERS | 6 +
drivers/iio/Kconfig | 1 +
drivers/iio/Makefile | 1 +
drivers/iio/potentiometer/Kconfig | 20 +++
drivers/iio/potentiometer/Makefile | 6 +
drivers/iio/potentiometer/mcp4531.c | 228 +++++++++++++++++++++++++++++++++++
6 files changed, 262 insertions(+)
create mode 100644 drivers/iio/potentiometer/Kconfig
create mode 100644 drivers/iio/potentiometer/Makefile
create mode 100644 drivers/iio/potentiometer/mcp4531.c
diff --git a/MAINTAINERS b/MAINTAINERS
index b60e2b2369d2..27862156c7a7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6600,6 +6600,12 @@ W: http://linuxtv.org
S: Maintained
F: drivers/media/radio/radio-maxiradio*
+MCP4531 MICROCHIP DIGITAL POTENTIOMETER DRIVER
+M: Peter Rosin <peda@axentia.se>
+L: linux-iio@vger.kernel.org
+S: Maintained
+F: drivers/iio/potentiometer/mcp4531.c
+
MEDIA DRIVERS FOR RENESAS - VSP1
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
L: linux-media@vger.kernel.org
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 4011effe4c05..7cc87f322655 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -73,6 +73,7 @@ source "drivers/iio/orientation/Kconfig"
if IIO_TRIGGER
source "drivers/iio/trigger/Kconfig"
endif #IIO_TRIGGER
+source "drivers/iio/potentiometer/Kconfig"
source "drivers/iio/pressure/Kconfig"
source "drivers/iio/proximity/Kconfig"
source "drivers/iio/temperature/Kconfig"
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index 698afc2d17ce..121c814e366b 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -23,6 +23,7 @@ obj-y += imu/
obj-y += light/
obj-y += magnetometer/
obj-y += orientation/
+obj-y += potentiometer/
obj-y += pressure/
obj-y += proximity/
obj-y += temperature/
diff --git a/drivers/iio/potentiometer/Kconfig b/drivers/iio/potentiometer/Kconfig
new file mode 100644
index 000000000000..fd75db73e582
--- /dev/null
+++ b/drivers/iio/potentiometer/Kconfig
@@ -0,0 +1,20 @@
+#
+# Potentiometer drivers
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "Digital potentiometers"
+
+config MCP4531
+ tristate "Microchip MCP45xx/MCP46xx Digital Potentiometer driver"
+ depends on I2C
+ help
+ Say yes here to build support for the Microchip
+ MCP4531, MCP4532, MCP4551, MCP4552,
+ MCP4631, MCP4632, MCP4651, MCP4652
+ digital potentiomenter chips.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mcp4531.
+
+endmenu
diff --git a/drivers/iio/potentiometer/Makefile b/drivers/iio/potentiometer/Makefile
new file mode 100644
index 000000000000..8afe49227012
--- /dev/null
+++ b/drivers/iio/potentiometer/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for industrial I/O potentiometer drivers
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_MCP4531) += mcp4531.o
diff --git a/drivers/iio/potentiometer/mcp4531.c b/drivers/iio/potentiometer/mcp4531.c
new file mode 100644
index 000000000000..82c24c6dcde0
--- /dev/null
+++ b/drivers/iio/potentiometer/mcp4531.c
@@ -0,0 +1,228 @@
+/*
+ * Industrial I/O driver for Microchip digital potentiometers
+ * Copyright (c) 2015 Axentia Technologies AB
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * Datasheet: http://www.microchip.com/downloads/en/DeviceDoc/22096b.pdf
+ *
+ * DEVID #Wipers #Positions Resistor Opts (kOhm) i2c address
+ * mcp4531 1 129 5, 10, 50, 100 010111x
+ * mcp4532 1 129 5, 10, 50, 100 01011xx
+ * mcp4551 1 257 5, 10, 50, 100 010111x
+ * mcp4552 1 257 5, 10, 50, 100 01011xx
+ * mcp4631 2 129 5, 10, 50, 100 0101xxx
+ * mcp4632 2 129 5, 10, 50, 100 01011xx
+ * mcp4651 2 257 5, 10, 50, 100 0101xxx
+ * mcp4652 2 257 5, 10, 50, 100 01011xx
+ *
+ * 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/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+
+#include <linux/iio/iio.h>
+
+struct mcp4531_cfg {
+ int wipers;
+ int max_pos;
+ int kohms;
+};
+
+static const struct mcp4531_cfg mcp4531_cfg[] = {
+ { /* MCP4531-502 */ .wipers = 1, .max_pos = 128, .kohms = 5, },
+ { /* MCP4531-103 */ .wipers = 1, .max_pos = 128, .kohms = 10, },
+ { /* MCP4531-503 */ .wipers = 1, .max_pos = 128, .kohms = 50, },
+ { /* MCP4531-104 */ .wipers = 1, .max_pos = 128, .kohms = 100, },
+ { /* MCP4532-502 */ .wipers = 1, .max_pos = 128, .kohms = 5, },
+ { /* MCP4532-103 */ .wipers = 1, .max_pos = 128, .kohms = 10, },
+ { /* MCP4532-503 */ .wipers = 1, .max_pos = 128, .kohms = 50, },
+ { /* MCP4532-104 */ .wipers = 1, .max_pos = 128, .kohms = 100, },
+ { /* MCP4551-502 */ .wipers = 1, .max_pos = 256, .kohms = 5, },
+ { /* MCP4551-103 */ .wipers = 1, .max_pos = 256, .kohms = 10, },
+ { /* MCP4551-503 */ .wipers = 1, .max_pos = 256, .kohms = 50, },
+ { /* MCP4551-104 */ .wipers = 1, .max_pos = 256, .kohms = 100, },
+ { /* MCP4552-502 */ .wipers = 1, .max_pos = 256, .kohms = 5, },
+ { /* MCP4552-103 */ .wipers = 1, .max_pos = 256, .kohms = 10, },
+ { /* MCP4552-503 */ .wipers = 1, .max_pos = 256, .kohms = 50, },
+ { /* MCP4552-104 */ .wipers = 1, .max_pos = 256, .kohms = 100, },
+ { /* MCP4631-502 */ .wipers = 2, .max_pos = 128, .kohms = 5, },
+ { /* MCP4631-103 */ .wipers = 2, .max_pos = 128, .kohms = 10, },
+ { /* MCP4631-503 */ .wipers = 2, .max_pos = 128, .kohms = 50, },
+ { /* MCP4631-104 */ .wipers = 2, .max_pos = 128, .kohms = 100, },
+ { /* MCP4632-502 */ .wipers = 2, .max_pos = 128, .kohms = 5, },
+ { /* MCP4632-103 */ .wipers = 2, .max_pos = 128, .kohms = 10, },
+ { /* MCP4632-503 */ .wipers = 2, .max_pos = 128, .kohms = 50, },
+ { /* MCP4632-104 */ .wipers = 2, .max_pos = 128, .kohms = 100, },
+ { /* MCP4651-502 */ .wipers = 2, .max_pos = 256, .kohms = 5, },
+ { /* MCP4651-103 */ .wipers = 2, .max_pos = 256, .kohms = 10, },
+ { /* MCP4651-503 */ .wipers = 2, .max_pos = 256, .kohms = 50, },
+ { /* MCP4651-104 */ .wipers = 2, .max_pos = 256, .kohms = 100, },
+ { /* MCP4652-502 */ .wipers = 2, .max_pos = 256, .kohms = 5, },
+ { /* MCP4652-103 */ .wipers = 2, .max_pos = 256, .kohms = 10, },
+ { /* MCP4652-503 */ .wipers = 2, .max_pos = 256, .kohms = 50, },
+ { /* MCP4652-104 */ .wipers = 2, .max_pos = 256, .kohms = 100, },
+};
+
+#define MCP4531_WRITE (0 << 2)
+#define MCP4531_INCR (1 << 2)
+#define MCP4531_DECR (2 << 2)
+#define MCP4531_READ (3 << 2)
+
+#define MCP4531_WIPER_SHIFT (4)
+
+struct mcp4531_data {
+ struct i2c_client *client;
+ unsigned long devid;
+};
+
+#define MCP4531_CHANNEL(ch) { \
+ .type = IIO_RESISTANCE, \
+ .indexed = 1, \
+ .output = 1, \
+ .channel = (ch), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+}
+
+static const struct iio_chan_spec mcp4531_channels[] = {
+ MCP4531_CHANNEL(0),
+ MCP4531_CHANNEL(1),
+};
+
+static int mcp4531_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct mcp4531_data *data = iio_priv(indio_dev);
+ int address = chan->channel << MCP4531_WIPER_SHIFT;
+ s32 ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = i2c_smbus_read_word_swapped(data->client,
+ MCP4531_READ | address);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 1000 * mcp4531_cfg[data->devid].kohms;
+ *val2 = mcp4531_cfg[data->devid].max_pos;
+ return IIO_VAL_FRACTIONAL;
+ }
+
+ return -EINVAL;
+}
+
+static int mcp4531_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct mcp4531_data *data = iio_priv(indio_dev);
+ int address = chan->channel << MCP4531_WIPER_SHIFT;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (val > mcp4531_cfg[data->devid].max_pos || val < 0)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return i2c_smbus_write_byte_data(data->client,
+ MCP4531_WRITE | address | (val >> 8),
+ val & 0xff);
+}
+
+static const struct iio_info mcp4531_info = {
+ .read_raw = mcp4531_read_raw,
+ .write_raw = mcp4531_write_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static int mcp4531_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ unsigned long devid = id->driver_data;
+ struct mcp4531_data *data;
+ struct iio_dev *indio_dev;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_err(dev, "SMBUS Word Data not supported\n");
+ return -EIO;
+ }
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+ data->devid = devid;
+
+ indio_dev->dev.parent = dev;
+ indio_dev->info = &mcp4531_info;
+ indio_dev->channels = mcp4531_channels;
+ indio_dev->num_channels = mcp4531_cfg[devid].wipers;
+ indio_dev->name = client->name;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct i2c_device_id mcp4531_id[] = {
+ { "mcp4531-502", 0 },
+ { "mcp4531-103", 1 },
+ { "mcp4531-503", 2 },
+ { "mcp4531-104", 3 },
+ { "mcp4532-502", 4 },
+ { "mcp4532-103", 5 },
+ { "mcp4532-503", 6 },
+ { "mcp4532-104", 7 },
+ { "mcp4551-502", 8 },
+ { "mcp4551-103", 9 },
+ { "mcp4551-503", 10 },
+ { "mcp4551-104", 11 },
+ { "mcp4552-502", 12 },
+ { "mcp4552-103", 13 },
+ { "mcp4552-503", 14 },
+ { "mcp4552-104", 15 },
+ { "mcp4631-502", 16 },
+ { "mcp4631-103", 17 },
+ { "mcp4631-503", 18 },
+ { "mcp4631-104", 19 },
+ { "mcp4632-502", 20 },
+ { "mcp4632-103", 21 },
+ { "mcp4632-503", 22 },
+ { "mcp4632-104", 23 },
+ { "mcp4651-502", 24 },
+ { "mcp4651-103", 25 },
+ { "mcp4651-503", 26 },
+ { "mcp4651-104", 27 },
+ { "mcp4652-502", 28 },
+ { "mcp4652-103", 29 },
+ { "mcp4652-503", 30 },
+ { "mcp4652-104", 31 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, mcp4531_id);
+
+static struct i2c_driver mcp4531_driver = {
+ .driver = {
+ .name = "mcp4531",
+ },
+ .probe = mcp4531_probe,
+ .id_table = mcp4531_id,
+};
+
+module_i2c_driver(mcp4531_driver);
+
+MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
+MODULE_DESCRIPTION("MCP4531 digital potentiometer");
+MODULE_LICENSE("GPL");
--
1.7.10.4
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Lars-Peter Clausen <lars@metafoo.de> |
|---|---|
| Date | 2015-09-23 15:30 +0200 |
| Subject | Re: [PATCH v5 2/2] iio: mcp4531: Driver for Microchip digital potentiometers |
| Message-ID | <qbShs-5pG-27@gated-at.bofh.it> |
| In reply to | #1231388 |
On 09/23/2015 01:57 PM, Peter Rosin wrote:
[...]
Looks pretty good.
One thing I'm concerned about is that this array
> +static const struct mcp4531_cfg mcp4531_cfg[] = {
> + { /* MCP4531-502 */ .wipers = 1, .max_pos = 128, .kohms = 5, },
> + { /* MCP4531-103 */ .wipers = 1, .max_pos = 128, .kohms = 10, },
> + { /* MCP4531-503 */ .wipers = 1, .max_pos = 128, .kohms = 50, },
> + { /* MCP4531-104 */ .wipers = 1, .max_pos = 128, .kohms = 100, },
[...]
> +};
> +
And the indices into the array defined here need to stay in sync. It is
really easy to mess this up by accident when a new entry is added. And it
will probably take a while to notice when this happens.
> +static const struct i2c_device_id mcp4531_id[] = {
> + { "mcp4531-502", 0 },
> + { "mcp4531-103", 1 },
> + { "mcp4531-503", 2 },
> + { "mcp4531-104", 3 },
[...]
> + {}
> +};
I see two options to solve this. Either define a enum with all the different
devices and use a symbolic name for the indices.
E.g.
enum mcp4531_type {
MCP4531_502,
MCP4531_103,
...
};
static const struct mcp5431_cfg mcp5431_cfg[] = {
[MCP4531_502] = {.wipers = 1, .max_pos = 128, .kohms = 5, },
[MCP4531_103] = {.wipers = 1, .max_pos = 128, .kohms = 10, },
...
};
static const struct i2c_device_id mcp4531_id[] = {
{ "mcp4531-502", MCP4531_502 },
{ "mcp4531-103", MCP4531_103 },
...
};
Or the second option is to directly assign the cfg struct as the driver data
in the device ID table.
E.g.
#define MCP4531_CFG(_wipers, _max_pos, _kohms) \
(kernel_ulong_t)&(struct mcp4531_cfg) { \
.wipers = _wipers, .max_pos = _max_pos, .kohms = _kohms }
static const struct i2c_device_id mcp4531_id[] = {
{ "mcp4531-502", MCP4531_CFG(1, 128, 5) },
{ "mcp4531-103", MCP4531_CFG(1, 128, 10) },
...
};
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Peter Rosin <peda@lysator.liu.se> |
|---|---|
| Date | 2015-09-23 14:00 +0200 |
| Subject | [PATCH v5 1/2] iio: resistance: Document that resistance can be output |
| Message-ID | <qbQSn-3fk-31@gated-at.bofh.it> |
| In reply to | #1231384 |
From: Peter Rosin <peda@axentia.se> Signed-off-by: Peter Rosin <peda@axentia.se> --- Documentation/ABI/testing/sysfs-bus-iio | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 9398484196c4..2eea468f704d 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1475,6 +1475,8 @@ Description: What: /sys/bus/iio/devices/iio:deviceX/in_resistance_raw What: /sys/bus/iio/devices/iio:deviceX/in_resistanceX_raw +What: /sys/bus/iio/devices/iio:deviceX/out_resistance_raw +What: /sys/bus/iio/devices/iio:deviceX/out_resistanceX_raw KernelVersion: 4.3 Contact: linux-iio@vger.kernel.org Description: -- 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web