summaryrefslogtreecommitdiff
path: root/drivers/iio/potentiometer/tpl0102.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-03-17 22:13:41 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-17 22:13:41 -0700
commit9dffdb38d864ae89e16ff7b3a09451270736e35b (patch)
tree709caf4ff2790a993ca11a40233ab241475451be /drivers/iio/potentiometer/tpl0102.c
parent10fdfee7f7fd8d4a6a8455ac4c9fbbc51d79b9f7 (diff)
parent2df122bdebaba1daad3a8087b89a5e3456474538 (diff)
Merge tag 'staging-4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
Pull staging driver updates from Greg KH: "Here is the big staging driver pull request for 4.6-rc1. Lots of little things here, over 1600 patches or so. Notable is all of the good Lustre work happening, those developers have finally woken up and are cleaning up their code greatly. The Outreachy intern application process is also happening, which brought in another 400 or so patches. Full details are in the very long shortlog. All of these have been in linux-next with no reported issues" * tag 'staging-4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (1673 commits) staging: lustre: fix aligments in lnet selftest staging: lustre: report minimum of two buffers for LNet selftest load test staging: lustre: test for proper errno code in lstcon_rpc_trans_abort staging: lustre: filter remaining extra spacing for lnet selftest staging: lustre: remove extra spacing when setting variable for lnet selftest staging: lustre: remove extra spacing of variable declartions for lnet selftest staging: lustre: fix spacing issues checkpatch reported in lnet selftest staging: lustre: remove returns in void function for lnet selftest staging: lustre: fix bogus lst errors for lnet selftest staging: netlogic: Replacing pr_err with dev_err after the call to devm_kzalloc staging: mt29f_spinand: Replacing pr_info with dev_info after the call to devm_kzalloc staging: android: ion: fix up file mode staging: ion: debugfs invalid gfp mask staging: rts5208: Replace pci_enable_device with pcim_enable_device Staging: ieee80211: Place constant on right side of the test. staging: speakup: Replace del_timer with del_timer_sync staging: lowmemorykiller: fix 2 checks that checkpatch complained staging: mt29f_spinand: Drop void pointer cast staging: rdma: hfi1: file_ops: Replace ALIGN with PAGE_ALIGN staging: rdma: hfi1: driver: Replace IS_ALIGNED with PAGE_ALIGNED ...
Diffstat (limited to 'drivers/iio/potentiometer/tpl0102.c')
-rw-r--r--drivers/iio/potentiometer/tpl0102.c166
1 files changed, 166 insertions, 0 deletions
diff --git a/drivers/iio/potentiometer/tpl0102.c b/drivers/iio/potentiometer/tpl0102.c
new file mode 100644
index 000000000000..313124b6fd59
--- /dev/null
+++ b/drivers/iio/potentiometer/tpl0102.c
@@ -0,0 +1,166 @@
+/*
+ * tpl0102.c - Support for Texas Instruments digital potentiometers
+ *
+ * Copyright (C) 2016 Matt Ranostay <mranostay@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * TODO: enable/disable hi-z output control
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+
+struct tpl0102_cfg {
+ int wipers;
+ int max_pos;
+ int kohms;
+};
+
+enum tpl0102_type {
+ CAT5140_503,
+ CAT5140_104,
+ TPL0102_104,
+ TPL0401_103,
+};
+
+static const struct tpl0102_cfg tpl0102_cfg[] = {
+ /* on-semiconductor parts */
+ [CAT5140_503] = { .wipers = 1, .max_pos = 256, .kohms = 50, },
+ [CAT5140_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, },
+ /* ti parts */
+ [TPL0102_104] = { .wipers = 2, .max_pos = 256, .kohms = 100 },
+ [TPL0401_103] = { .wipers = 1, .max_pos = 128, .kohms = 10, },
+};
+
+struct tpl0102_data {
+ struct regmap *regmap;
+ unsigned long devid;
+};
+
+static const struct regmap_config tpl0102_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+#define TPL0102_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 tpl0102_channels[] = {
+ TPL0102_CHANNEL(0),
+ TPL0102_CHANNEL(1),
+};
+
+static int tpl0102_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct tpl0102_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW: {
+ int ret = regmap_read(data->regmap, chan->channel, val);
+
+ return ret ? ret : IIO_VAL_INT;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ *val = 1000 * tpl0102_cfg[data->devid].kohms;
+ *val2 = tpl0102_cfg[data->devid].max_pos;
+ return IIO_VAL_FRACTIONAL;
+ }
+
+ return -EINVAL;
+}
+
+static int tpl0102_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct tpl0102_data *data = iio_priv(indio_dev);
+
+ if (mask != IIO_CHAN_INFO_RAW)
+ return -EINVAL;
+
+ if (val >= tpl0102_cfg[data->devid].max_pos || val < 0)
+ return -EINVAL;
+
+ return regmap_write(data->regmap, chan->channel, val);
+}
+
+static const struct iio_info tpl0102_info = {
+ .read_raw = tpl0102_read_raw,
+ .write_raw = tpl0102_write_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static int tpl0102_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct tpl0102_data *data;
+ struct iio_dev *indio_dev;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WORD_DATA))
+ return -ENOTSUPP;
+
+ 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->devid = id->driver_data;
+ data->regmap = devm_regmap_init_i2c(client, &tpl0102_regmap_config);
+ if (IS_ERR(data->regmap)) {
+ dev_err(dev, "regmap initialization failed\n");
+ return PTR_ERR(data->regmap);
+ }
+
+ indio_dev->dev.parent = dev;
+ indio_dev->info = &tpl0102_info;
+ indio_dev->channels = tpl0102_channels;
+ indio_dev->num_channels = tpl0102_cfg[data->devid].wipers;
+ indio_dev->name = client->name;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct i2c_device_id tpl0102_id[] = {
+ { "cat5140-503", CAT5140_503 },
+ { "cat5140-104", CAT5140_104 },
+ { "tpl0102-104", TPL0102_104 },
+ { "tpl0401-103", TPL0401_103 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, tpl0102_id);
+
+static struct i2c_driver tpl0102_driver = {
+ .driver = {
+ .name = "tpl0102",
+ },
+ .probe = tpl0102_probe,
+ .id_table = tpl0102_id,
+};
+
+module_i2c_driver(tpl0102_driver);
+
+MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_DESCRIPTION("TPL0102 digital potentiometer");
+MODULE_LICENSE("GPL");