Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751583AbdISHHI (ORCPT ); Tue, 19 Sep 2017 03:07:08 -0400 Received: from mail-cys01nam02on0091.outbound.protection.outlook.com ([104.47.37.91]:4256 "EHLO NAM02-CY1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1750982AbdISHHF (ORCPT ); Tue, 19 Sep 2017 03:07:05 -0400 From: Ismail Kose Cc: "Ismail H. Kose" , Jonathan Cameron , Hartmut Knaack , Lars-Peter Clausen , Peter Meerwald-Stadler , Rob Herring , Mark Rutland , Fabrice Gasnier , Peter Rosin , Maxime Roussin-Belanger , Mike Looijmans , Jean-Francois Dagenais , linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4] iio: dac: ds4422/ds4424 dac driver Date: Tue, 19 Sep 2017 00:06:43 -0700 Message-Id: <20170919070652.23874-1-Ismail.Kose@maximintegrated.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [204.17.143.20] X-ClientProxiedBy: YQXPR0101CA0055.CANPRD01.PROD.OUTLOOK.COM (52.132.74.32) To MWHPR11MB1872.namprd11.prod.outlook.com (10.175.54.7) X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 21be6afe-17da-49e1-c345-08d4ff2d06dd X-MS-Office365-Filtering-HT: Tenant X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:(300000500095)(300135000095)(300000501095)(300135300095)(22001)(300000502095)(300135100095)(2017030254152)(48565401081)(300000503095)(300135400095)(2017052603199)(201703131423075)(201703031133081)(201702281549075)(300000504095)(300135200095)(300000505095)(300135600095)(300000506095)(300135500095);SRVR:MWHPR11MB1872; X-Microsoft-Exchange-Diagnostics: 1;MWHPR11MB1872;3:Kpc1+unliD6ivmvmySoturuZvHHyQEFC+Af7vMozyNCOmrt98fu5byVvKQ4h2o/g1Zs/USq6dmC17CuapsObomYdVy6D05A1PVbRhL9yXz+ZkvGzUeRnlYKDhi2KU8SYYJ1zMLwpcEIXOhdTpviU+l+sK9kUhtff/N+oO9codzrckdLCCCr9qr/KxTkQmU3djUatV8SEagr+xgorebZp8TLZ5HIp8VtdcsRYAT2sFybAINK1UKxwSj04EQc7WkYQ;25:iy8PFik1aSIS4/UeQWIN+476lPkCZ3jrB0+jXDLfdBt0kyEr16krqWXgoNrrRRCIeHHPsozWcDEdbbhJl/M6bmn1T7qjymb3uQLFHeQfSJT+j6vwuoLp91r1Y1vHoKI+I7TAPk4SuKRlFQdRwKB9JMxWTbC09T493Kc9838xSBcNWPuOVVxznfEXI/O9X3vCkt/+xueu6L4UT7OUWBvhz5oXWIz8KO3wTP5UDGswuKRyUCcEbEaj+BiCYoomyk+yVcorzvnRZFOi8iv/6NZAE+GUqBFF33ad4Ye8XlIJFyLPFHTStFg5D/jUqgDwCFC87vyJoYMBKZrTa+ul80URwA==;31:RgGIJkHrd/deRjbCvprrs+Pyhhd3yjSs8nipE1zx+pMJvtJO2jvsUINHf1+KkLY65NQ3D/Y7FAKlPpfDZjz9f/QUh8/ifBy2NfmeeSyvCrzDl62Rcqz3uf/fRzuXo/fOxjK+BZvI1Yy9rGGV/6Ow+Q9Zr6+4nnyIXgsK+lkDswCAV0v1wvgb+dmWQXxs/wDWiTPIDwh2ptSRWblwFH/h+Zs5P6M7zmEuwoev5+SyRK0= X-MS-TrafficTypeDiagnostic: MWHPR11MB1872: Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Ismail.Kose@maximintegrated.com; X-Microsoft-Exchange-Diagnostics: 1;MWHPR11MB1872;20:loRm9wtI0/PUE4bjqfxK0MCXr5eOQRGTqQkciGDOn/mI7mGhW5wu9OJFav+qQVsreoHpygJeWaZFWnPYzj43IhdKbG8Mgdgi6HmBBJlGukqm9NbSUojR7OCPsqSrLl9O3PLsXR6UfPJAUxLBTni1d3C6fwLpYsxmRLOsRcYr9wbfukWohCJtHdHbJWISYNJSBBobNztzTbcFIrovcXkyjSGh2Mq6tI14xoqbNK0gYCRkS83l0OnM6JIIy82GzrQ/YYwYNSUHIOZVj4D/8sLUhMbEtwqn3vIAswqwjKeCsiHXXJZR01RjfW3DF3dFjw4d8R4r1cBK5jx3em7QQP3l6Og2bu4kfE6Bmhhy1hsbebuP01UIkMiilzEijQxdtA+qTVljTST0FpNCdppAc/ODUW3s5UGy9+DpLNJ8glYBdIsIWx3fzVcv2Me99AuZfT0ywDqdngPfVqgScqYO515QmwACTciofQnY5WBYzVKg2+GlT1inH79Vg/NL+vor6Av4;4:xQQku82EJ65Jg/1bUMfHraMvXPZPbgqsOrgRoWkIVK4RwO5bwTcSP6Vk+41Y2aWLo27hcnAZ0C+jdBDTYkzjW7QnmiGjKB9LVlwroRjNAV13RO/+lOLvHOcXOS9IcwGfI2aS1zAaaL2DLowYlddKKlPd06UHO2OurUu71lraueY5En85c7CAKAVe5Pk6/zH7BKukSnZEO8hMZBidFvWFP8pqo/nhJx1pt4O1j0QPTpQ2LgSmHkYdnzU5k7d5RDTV+I2nq/ZupYdud1YQpb5wOWIMKqIssKUOyL6tkaGMT9Y= X-Exchange-Antispam-Report-Test: UriScan:(108721460000369); X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(100000700101)(100105000095)(100000701101)(100105300095)(100000702101)(100105100095)(6040450)(2401047)(5005006)(8121501046)(3002001)(100000703101)(100105400095)(93006095)(93001095)(10201501046)(6055026)(6041248)(20161123562025)(201703131423075)(201702281528075)(201703061421075)(201703061406153)(20161123558100)(20161123555025)(20161123560025)(20161123564025)(6072148)(201708071742011)(100000704101)(100105200095)(100000705101)(100105500095);SRVR:MWHPR11MB1872;BCL:0;PCL:0;RULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(100000804101)(100110200095)(100000805101)(100110500095);SRVR:MWHPR11MB1872; X-Forefront-PRVS: 04359FAD81 X-Forefront-Antispam-Report: SFV:NSPM;SFS:(10019020)(6009001)(346002)(39860400002)(376002)(189002)(199003)(50226002)(50986999)(106356001)(76176999)(189998001)(105586002)(6506006)(36756003)(25786009)(109986005)(8936002)(86362001)(39060400002)(81166006)(4326008)(8676002)(81156014)(72206003)(101416001)(69596002)(6486002)(6116002)(2906002)(68736007)(3846002)(50466002)(66066001)(54906002)(6306002)(6512007)(47776003)(5660300001)(16586007)(53936002)(5003940100001)(316002)(7416002)(1076002)(48376002)(16526017)(1671002)(7736002)(8666007)(53416004)(478600001)(97736004)(6666003)(2950100002)(305945005)(266003)(2004002);DIR:OUT;SFP:1102;SCL:1;SRVR:MWHPR11MB1872;H:kose.maxim-ic.com;FPR:;SPF:None;PTR:InfoNoRecords;MX:1;A:1;LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;MWHPR11MB1872;23:yCnAIWLGRrNEef2A/0o76PfnsTbXSnm2Emum7MpWz?= =?us-ascii?Q?AmU/1AYEpJMVtRJkRRhaNiNM3tvpRJJQ2vbYKFxoALa9kdk/a2upCPkw/2YV?= =?us-ascii?Q?9hH8vOPs3idzSPcULP5M2c0V27MZDhuhUtCca7YuZfpl2PorMT0ajxZHhFjH?= =?us-ascii?Q?hEpZczZI08FpNJSY4ACIOVag76Ke6d7LMpBDRN4V/XLAiTS5OBufD+xS/5tM?= =?us-ascii?Q?9p+p9Gav1yqXC33o+otX3JZ1UtJqvT+qUG6t+JYBxLurho7g2eHJbiL2PCst?= =?us-ascii?Q?DNnIgcbYR8FBu2+do5mTKrW+zcLbR1BNOaEN2mawUUnVV+ql/6F+NYKYMffV?= =?us-ascii?Q?zlvH5JzhUa3fNaImih0TcWb7TCsXwJN3JP8DbqUU5Oe3hHyhcHyqVXz+cLQ3?= =?us-ascii?Q?8sL6tHexH3CRINiUoqNMgT2iJ4yAWnJzojKLbKogt+1vECZsRa9izfHp5W7I?= =?us-ascii?Q?WHLKzI9Kx8pb1jejP8o7+RiejMC+ynCRljQu7u1eT8xtehRiBYN+7eciaGx0?= =?us-ascii?Q?6Z/Oa0NqBsdCj9Y9cBpSPk6JSbIRGQxNLPfm9EE89oOxOziVUi22R9OxdcTX?= =?us-ascii?Q?IoSE0UiJhAqicsqtoE78G3dBBLiDS/2sVLLqd7mWwWTpxd7GMUXpy4WWNOCn?= =?us-ascii?Q?DveplqlgJDOZg3agoBswE3qoXQDtdEjVwEq2tVmiZW0vvsnJUYr+QYOuZiov?= =?us-ascii?Q?YnMXzH9er8EW4Lj/JafACbzqSy1NsuDeP3wRstIyS6mkcGRp/hgI2iJynQpC?= =?us-ascii?Q?zY8vaDJUU+D2HICb6sqsNGcGO61fsTHBtlF3UkekkJOjE5nBUl4lG8wMTL3N?= =?us-ascii?Q?jCVe70oqZBhg2/7pgJsmxN8H+CcGF09q2B2J/r/HBT+EFpbNUG6WWAMBGph4?= =?us-ascii?Q?nsO56IRZR2WlDn9p+eZ5d+zMsPxU/7t2vG/pCjRMtNo3Nm0NmdF/BkQe0WJu?= =?us-ascii?Q?0q3IJySbu3LXyZjKqNfvhgUyITAjvQY/lvI6rPw1iOsX4uhnHB2MYiR+jqus?= =?us-ascii?Q?hCi/zwi1UOVajFq96g7FapcjNB9Xmp7pY0RszwihAeqRXDOzfV0j744QsKk8?= =?us-ascii?Q?E38BTS8SxZzB4FCJ5IZY76aF1VQaBh1C0H+1kmHqUNYvzkI6hyUPLVYFvsxV?= =?us-ascii?Q?+bd5rx9u+kMK/+DI9TDm6mZqPUhaozN1wUXBZ760GZQTj3l9mOy+DOv79ne6?= =?us-ascii?Q?t7IdX5i7wN1nrltjYVq2zSirYcKITYKvpjYjvdZ6teZt3hmgigPSbS12YF0B?= =?us-ascii?Q?kbx2HXwBtdb2SdbZviUnmJ/h+vBg7QYEpBYvrDR+vDT4mDhDRuD/pqXUnPsx?= =?us-ascii?Q?qyqeGj4LLiaRmnSDMclBX4=3D?= X-Microsoft-Exchange-Diagnostics: 1;MWHPR11MB1872;6:G63b0AlkHmEOwAzjS3qYLk+M5tj8weNxY9VeHHrpvHJe/Bvw9PKhPHzhc8tqOOeCU3qF7Xnc0AFi8CGgAoBCtTMGvSpL1LFz3+JmmfL4NstVHPTMT+NAQQfzBFLdkQx7qBYo+ytuj+dNsMvolcsbZbWbXrYSSHBYsNTC7zUFgWh2HYSm8rEc69uyd6NDdmlnEQKGdk0ONoQgNYM6ecChZn5cGL3nYqkx0n0espRQY2TkdiNg9daqtMTgxMRFWiNfVJf9QdlN2vSqufktAhoUXuLZtP0kf5SnJJJ/f8gXRI3Dzjkmy/NsGJUF4cEqUjiTnTeMUW7ns/CV2vgW0pwWaQ==;5:kKJvOpRoMQQw2vIF39lrm3YA2KacMkS8sBy/KUrKYlcGb+JHMcxwWz3E5LJExYkQY/8KOqyR7ePWoIkXIWv5Ubd7W/ObGY72oYnS+Y1nv+0BCrFoOD0HAwQDb7nAeP1hPZO+9ktgggvUOamRJlsIyQ==;24:7vWDO7QmzArhLHa+/kTEaWphH1uyfZB/8syNkG78tin0xXdy4qC4YtUqV8cJ2AX3gwQUgXjV8QaGiNaitWqLe8lKxxLWce+c/PN6DC+rV6s=;7:9gfCm2upzzmQdDGx0fTApn1bpT5VtF0IL66CufHr6ztuRNa34LGdLsD8r8O5wtRU3A5DMkl8CiyW6XAoKG4darCu0RD/RWXgV4V/3Kqfajue8/b5fkfM0ciCwRcR7VSXN/4ld1hQffbZL29SRhTzpvlvKIJVfE32mVamh9VAafFpS1KV6lDwB8J6T0YCVG4Ps02kMkSIiHULA5TtvdHOkp3mdbw8DTuxIlqvKDZW3/I= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: maximintegrated.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 19 Sep 2017 07:06:59.4109 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: fbd909df-ea69-4788-a554-f24b7854ad03 X-MS-Exchange-Transport-CrossTenantHeadersStamped: MWHPR11MB1872 To: unlisted-recipients:; (no To-header on input) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 12861 Lines: 495 From: "Ismail H. Kose" This patch provides an iio device driver for DS4422/DS4424 chips that support two/four channel 7-bit Sink/Source Current DAC. Signed-off-by: Ismail Kose --- v4: * Removed unnecessary code and space optimization * Alphabetic order in Kcobfig and Makefile v3: * Removed iio-map and platform file support * Removed ds4424.h file * Fixed ADC value read bug * Removed confused comments * Added device tree binding file * Fixed bugs in probe and read function v2: (https://lkml.org/lkml/2017/9/14/546) * Fixed coding style and removed unncessary code * Removed min/max rfs, ifs-scale, etc values from device tree * Removed unused code, definitions and some comments * Removed regulator control and made standard structure * Removed data processing and channel scale * Removed device tree binding file .../devicetree/bindings/iio/dac/ds4424.txt | 20 ++ drivers/iio/dac/Kconfig | 9 + drivers/iio/dac/Makefile | 1 + drivers/iio/dac/ds4424.c | 395 +++++++++++++++++++++ 4 files changed, 425 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/dac/ds4424.txt create mode 100644 drivers/iio/dac/ds4424.c diff --git a/Documentation/devicetree/bindings/iio/dac/ds4424.txt b/Documentation/devicetree/bindings/iio/dac/ds4424.txt new file mode 100644 index 000000000000..840b11e1d813 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/dac/ds4424.txt @@ -0,0 +1,20 @@ +Maxim Integrated DS4422/DS4424 7-bit Sink/Source Current DAC Device Driver + +Datasheet publicly available at: +https://datasheets.maximintegrated.com/en/ds/DS4422-DS4424.pdf + +Required properties: + - compatible: Must be "maxim,ds4422" or "maxim,ds4424" + - reg: Should contain the DAC I2C address + - maxim,rfs-resistors-ohms: Should contain reference resistor + +Optional properties: + - vcc-supply: Power supply is optional. If not defined, driver will ignore it. + +Example: + ds4224@10 { + compatible = "maxim,ds4424"; + reg = <0x10>; /* When A0, A1 pins are ground */ + vcc-supply = "dac_vcc_3v3"; + maxim,rfs-resistors-ohms = <400 800 1000 1600>; + }; diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 25bed2d7d2b9..57c179830981 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -211,6 +211,15 @@ config AD8801 To compile this driver as a module choose M here: the module will be called ad8801. +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 DPOT_DAC tristate "DAC emulation using a DPOT" depends on OF diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 603587cc2f07..abf5c3094454 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_AD5686) += ad5686.o obj-$(CONFIG_AD7303) += ad7303.o obj-$(CONFIG_AD8801) += ad8801.o obj-$(CONFIG_CIO_DAC) += cio-dac.o +obj-$(CONFIG_DS4424) += ds4424.o obj-$(CONFIG_DPOT_DAC) += dpot-dac.o obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o obj-$(CONFIG_LTC2632) += ltc2632.o diff --git a/drivers/iio/dac/ds4424.c b/drivers/iio/dac/ds4424.c new file mode 100644 index 000000000000..f9d45c66bc15 --- /dev/null +++ b/drivers/iio/dac/ds4424.c @@ -0,0 +1,395 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + __maybe_unused uint8_t save[DS4424_MAX_DAC_CHANNELS]; + uint32_t rfs_res[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; + mutex_unlock(&data->lock); + return 0; + +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) { + mutex_unlock(&data->lock); + return ret; + } + + data->raw[chan->channel] = val; + mutex_unlock(&data->lock); + + return 0; +} + +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, +}; + +#ifdef CONFIG_OF +static int ds4424_parse_dt(struct iio_dev *indio_dev) +{ + int ret; + int len; + int count; + struct property *prop; + struct ds4424_data *data = iio_priv(indio_dev); + struct device_node *node = indio_dev->dev.of_node; + + if (!node) { + pr_info("%s:%d ds4424 DT not found\n", __func__, __LINE__); + return -ENODEV; + } + + prop = of_find_property(node, "maxim,rfs-resistors-ohms", &len); + if (!prop) { + pr_err("ds4424 maxim,rfs-resistor not found in DT.\n"); + return -EINVAL; + } + + if (len != (DS4424_MAX_DAC_CHANNELS * sizeof(uint32_t))) { + pr_err("ds4424 maxim,rfs-resistor length in DT not valid.\n"); + return -EINVAL; + } + + ret = of_property_read_u32_array(node, "maxim,rfs-resistors-ohms", + data->rfs_res, DS4424_MAX_DAC_CHANNELS); + if (ret < 0) { + pr_err("ds4424 reading maxim,rfs-resistors from DT failed.\n"); + return ret; + } + + pr_info("ds4424 maxim,rfs-resistors: %d, %d, %d, %d\n", + data->rfs_res[0], data->rfs_res[1], + data->rfs_res[2], data->rfs_res[3]); + + return 0; +} +#else +static int ds4424_parse_dt(struct iio_dev *indio_dev) +{ + return -ENODEV; +} +#endif + +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 -EPERM; + } + + indio_dev->dev.of_node = client->dev.of_node; + ret = ds4424_parse_dt(indio_dev); + if (ret < 0) { + dev_err(&client->dev, + "%s - of_node error\n", __func__); + return -EINVAL; + } + + data->vcc_reg = devm_regulator_get(&client->dev, "vcc"); + if (IS_ERR(data->vcc_reg)) { + ret = PTR_ERR(data->vcc_reg); + dev_err(&client->dev, + "Failed to get vcc-supply regulator: %d\n", ret); + return ret; + } + + 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) + return -ENXIO; + + 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"); + regulator_disable(data->vcc_reg); + return -ENXIO; + } + + 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); + 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 "); +MODULE_AUTHOR("Vishal Sood "); +MODULE_AUTHOR("David Jung "); +MODULE_LICENSE("GPL v2"); -- 2.11.0