From patchwork Fri Sep 22 20:12:08 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ismail Kose X-Patchwork-Id: 9967025 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id DEBEF60381 for ; Fri, 22 Sep 2017 20:13:24 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CFC38285D3 for ; Fri, 22 Sep 2017 20:13:24 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C441C2882E; Fri, 22 Sep 2017 20:13:24 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A8B8F285D3 for ; Fri, 22 Sep 2017 20:13:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751951AbdIVUNW (ORCPT ); Fri, 22 Sep 2017 16:13:22 -0400 Received: from mail-sn1nam01on0104.outbound.protection.outlook.com ([104.47.32.104]:47520 "EHLO NAM01-SN1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751878AbdIVUNU (ORCPT ); Fri, 22 Sep 2017 16:13:20 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=maximintegrated.onmicrosoft.com; s=selector1-maximintegrated-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=3v0spIIALybqxfnRrBDpwDrPJ8Fup8itHeXuhB1qpHU=; b=tci9eYgamdzFQZdeztx2EgmUI9Q9WRRb6iKJslyg7c9G8y6w0vMQQ9mplR/C6TS59CowVkvvnT/XXOFr5j1epczvCesBlUyO/LdkH1eiZiOQdHJALURbk0k1vfsyRZUpl9QUdJYgTLW7lgnW4G3SOodAL8ZgxfkIHRee0tVHr9c= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Ismail.Kose@maximintegrated.com; Received: from kose.maxim-ic.com (204.17.143.20) by BN6PR11MB1857.namprd11.prod.outlook.com (10.175.99.149) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.77.7; Fri, 22 Sep 2017 20:13:14 +0000 From: "Ismail H. Kose" Cc: ihkose@gmail.com, Ismail.Kose@maximintegrated.com, Jonathan Cameron , Hartmut Knaack , Lars-Peter Clausen , Peter Meerwald-Stadler , Rob Herring , Mark Rutland , Mike Looijmans , Peter Rosin , Fabrice Gasnier , Maxime Roussin-Belanger , Jean-Francois Dagenais , linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v6 1/2] iio: dac: ds4422/ds4424 dac driver Date: Fri, 22 Sep 2017 13:12:08 -0700 Message-Id: <20170922201226.23721-1-Ismail.Kose@maximintegrated.com> X-Mailer: git-send-email 2.11.0 MIME-Version: 1.0 X-Originating-IP: [204.17.143.20] X-ClientProxiedBy: CY4PR0601CA0102.namprd06.prod.outlook.com (52.132.96.171) To BN6PR11MB1857.namprd11.prod.outlook.com (10.175.99.149) X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: e9538008-bf18-4746-34f0-08d501f65be8 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:BN6PR11MB1857; X-Microsoft-Exchange-Diagnostics: 1; BN6PR11MB1857; 3:0IKapmOUQRE96tuXzTRv7oVdLPbc809CKBZgPTunt9GVnTj5yrewBtV0qvGTFypbJ/uJPe92zTDoPR7ssVUgJsU3qzHlfMwg34R4I4fneim2sYMdc8ZPj4HGR7lW0CWBmpWOWBSr/C1elcKCm2xI/I4hV3e2imxR3I9fCFoXGYuEy3HdBkTBsIxCeW4BfQE0GPft3I5mIPqudvCppD0k1XJdJjfL7/gEyBjwZt8zFD/pRRxfA3pC+YizKAQPYe4M; 25:e+FJ8s3Dy2Ey/P1mk3SwdofXjXtk5XHT6lM0H6mFdNg2lI/l+aelBYhp/XQe77GaY7n2CO5xvEwnEo17aHivx42G6mCQ1iwaNXO2WBAgeSoGzMOKVrgoTAgpAIQd4nLd0Y3YosVUcIRbJ3ICDSF03uV4ab/2c8GypxfvYEVbQag4oS8Lpz0nC5t+hVJlQu+j8F0lW2yQj9IvUV17NkxxFSBm6k4q/gjaJFflNI7vSFb4cYkajzuEFP1EuwvrPX6PFbU/uUiEswg5qGmVC5yNaIOGmIMmhWe4ujZsIr28+f+teWHCOVmuveV9g1DLnB17msyX6wx06+OsOC5UAJ0OMg==; 31:kqBm2HQGvksqNJOyDlL7gOnuGx/DTGKRUZpyViztpDDq99sRGHj3uZ3YWtYXwHQk/pcH0c/+w38sp2YTf9hvBvHYedhEuH6x+JnGUbyU7NZShBlg4z4SWjGizkgWq/71Xoxv4asnsYI6ufGuleNmWx8pUDLq2WnZZIXayiIE2QeRi6JuGOPjY2gQjOUjpyNs/+PlisggnDYrvJnH/R2tXrR4QL3yd2t3gpoSweXnMuE= X-MS-TrafficTypeDiagnostic: BN6PR11MB1857: X-Microsoft-Exchange-Diagnostics: 1; BN6PR11MB1857; 20:VfK2eEgkKnNWFjUkWGtpO5VjRdQGqtJw913BnaXgC3BNFwej1sgh8r0BkG6Kacu5zj9V7sbGsSMQKLt/8HicDZDPKP1qPMMvtYUqoIW+sbR7CQiVVnXl21l5OZw9GyYiUz4VQjJgexyrtjJcVUghxtULE6vwGeZwViFF+PgBumj+zuHOmR4Mq9rCGBwLypU+SoMURRflPx+TfmQJDzsB5+PMdI4XAdIExrXLLbmQOri2nVzCqIjqzcvlQW9OqSzuUpmzmj0W4FYvcxf+IaWurfYasV3tUr6idvOdeSKhsr+JZH5O60SLk+7EmxGKLMlnEEQv84q2vbiHpwDqqOqvNJ+X19PRy2h0yoc5JRRByG3k6pS1vCloooonVf7nj+6F2SG27Ooo/2RaVzB88LJaveB4BJr/LBPhh3e1yoc/imcdoihZtz6BppvXf3BKlIbW+n6Jw2FIK4/btqZ+29nra5Yaa41OfhBq0sM9/uQ7381R3cDwoh1zS4BLHmBmFY8O; 4:h9YFUR/Dx7zER9jh5EqZZL8gnk5tUPzaSguLdNYV6fMnwkwuQPEJI/4YZE3KcHvZ+Xd/ay9M/2f+NmsJKvpAO63xL5uJ5JfgNoJSt3ly/3iqFu5Aew0mTFlr05Nxsb4JicjF1tlhp+BM0BFNRB8pKr1ngrsXpB80GSonlqnq0CeWZ2VkvZBLluAmpxrMjyXXCZBHjsN/E+LdRgiHbP3rD5U3/b21+eZrudxhA7Csn0m7/WB0OowKRJueqW74m1/FY2IDVXsO3bNQOcxvTEzv/nOKRfXyeSad0BHNxKlfEc0= 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)(8121501046)(5005006)(93006095)(93001095)(100000703101)(100105400095)(10201501046)(3002001)(6055026)(6041248)(20161123555025)(20161123562025)(20161123558100)(20161123560025)(201703131423075)(201702281528075)(201703061421075)(201703061406153)(20161123564025)(6072148)(201708071742011)(100000704101)(100105200095)(100000705101)(100105500095); SRVR:BN6PR11MB1857; BCL:0; PCL:0; RULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(100000804101)(100110200095)(100000805101)(100110500095); SRVR:BN6PR11MB1857; X-Forefront-PRVS: 0438F90F17 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(6009001)(346002)(376002)(39860400002)(189002)(199003)(86362001)(575784001)(25786009)(16526017)(6666003)(36756003)(53936002)(316002)(48376002)(105586002)(81156014)(50226002)(106356001)(6486002)(54906003)(16586007)(2906002)(8676002)(97736004)(3846002)(8936002)(109986005)(50466002)(8666007)(5660300001)(6512007)(81166006)(1671002)(305945005)(72206003)(47776003)(68736007)(7416002)(6506006)(5003940100001)(7736002)(4326008)(1076002)(69596002)(50986999)(6116002)(66066001)(39060400002)(189998001)(53416004)(101416001)(478600001)(266003)(2004002); DIR:OUT; SFP:1102; SCL:1; SRVR:BN6PR11MB1857; H:kose.maxim-ic.com; FPR:; SPF:None; PTR:InfoNoRecords; MX:1; A:1; LANG:en; Received-SPF: None (protection.outlook.com: maximintegrated.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; BN6PR11MB1857; 23:BbUL16PYRssqlP7wLx+mF3Z8pNJrQh0ImqJCEbolI?= =?us-ascii?Q?X58Yyx3qXZkSsF2zOmiHggLPXUpXKvPBijeYa8l32ni2ZzRo58bLIGzpD/2v?= =?us-ascii?Q?H16O/1SIverZKw7BbpC/RMP4UJMVzkSUc7qbMZeJkDCSXu3kdWW+NmEOa8t8?= =?us-ascii?Q?V7DR5PNgrlIxCILVHCuWzRKb0eLJ1D8YYSvcfcpQ4fyozHaohR4js65gNdbI?= =?us-ascii?Q?JzkFX6R1aqbgHHupo5SmzJ8Mp/iweAow3O07LIw4E0srncHs+xJ6aTIM8krF?= =?us-ascii?Q?fNC26+R5Woafyj9UmXV6EsZX/QNzcxcCv93jSpaY4M8Xs0Ox7gxp6M22P4d5?= =?us-ascii?Q?HHvJBKL5tLlpJS4Q6FKFmH2y3+l05R7qGI+DDtGGkK9TW+fcCJWbLw/3x7fx?= =?us-ascii?Q?5m2rxv8p7TuLvVnpThYpWzeZqyyXhjHVcwm/RWw5T1lOIWCjlyEx6L17t7p+?= =?us-ascii?Q?porixMyit4rEocW/aUHg8lofJS2L5Ba3+xmCFGgdX1Fhvzw749Ttx/NR80hQ?= =?us-ascii?Q?bNI0MSvjVKlNcNKHn2NGvOzaVrVvWnH4b9YBFQ5Z4rmJl8TBokfnGM+invDG?= =?us-ascii?Q?qSwo4Q06/FOKWTOaJJ1YPuIVsY6hoX1fJi6EL+y6s2Ejr80uG/4oFs9mmYso?= =?us-ascii?Q?v6j8DrvePOWZGfu0QQrrIjpF+rKrangcCtt5DJ12mkShx3FIilfQfK9jrlcX?= =?us-ascii?Q?tzssVFpuKVMolxEuFlRBkHtc62fRp/H040qb/6ODvQvIbjY8F85O/DJaUrCO?= =?us-ascii?Q?N2ZrylqLKdTXxGMNPkvXh1zskfn9U/GxjsgEBvlgkBQ4H0i8+yJa9FPuYFwj?= =?us-ascii?Q?dcop6OA5LFcA1QuwavchPUn9kYJFH/iTIXRj/0OoNOv32Ip/MO5wVeZuuM1h?= =?us-ascii?Q?PlD9T0o4KD8XSJY9Mg+jVyNaJZ7vVOBIAO4Q/T7MdkOBnTf94dSetaH9YReT?= =?us-ascii?Q?aXz+sqAHaQfVBZM0/RBMpne2mOk3uTlywoq9Wud4AIsHUGxPOlUSNPi8f9IK?= =?us-ascii?Q?aN/8+3q6UBBAQV/WpNpzfWxxgs6TDRc5V6f2hqUfWP8DolD5FYggO+C9KE8g?= =?us-ascii?Q?vXvWPT2uav1xwlL86Pnzl4FLYFiyL7dU2rD4rxe/pGZBWo3G5wkZ1Ci4z8TO?= =?us-ascii?Q?x66jX9b6jr9BhTTYLbLzzqzGFvv2TPO6zry4beYLVLIaop/zymjsEEWRf1IL?= =?us-ascii?Q?sN7R0+MoWVIaoiNpNHIxU/YZiVJBmx80k1uXNrt7bik1crlHxuEqHcHf5sjb?= =?us-ascii?Q?zOLNOSoQ1/rvIwxjiGpvDC9LKzsKsnGiEOUijhT?= X-Microsoft-Exchange-Diagnostics: 1; BN6PR11MB1857; 6:KaKRPuro0RSUwZux10OJe0fxrlgN+Bqh7U6NQrMbvBGVlUNRKbNh6fu6UUJncdM30/zBm1WXEDbSCshxJ2YsWVDRel7N9AYMdIfxv64wPLoPxx905MXlpb4Mv+V1WCK8CnCPV00PRnBG+h+7V9TqoiFYOdJw3zH0L+bcL9+E5jd+PLN1vCe9l8YIInY7EbPz3ApvvaX3vTkZ4x0aMx6T/5QFvirt2A4WUTA4d5FdluFCQumLtEKsAt2bwH8h0rHtQrMmpdVD54+h9rwsfjOzb8XTRRC8hfXzng6N0gx9RSxvB+J6MOp6UuDB1J5uFSWFrhmAP+v1LHiHxtDoQqqshA==; 5:G+S+FUGGev4/4EHCdfPMi8COraOkffVasLYw/ayTVW4kv+VWzFC0wb4bDguLecU3rZJgZOql80o/X3NC3yapEJGrlyfBROaCkzOluaALsaMx2jmsN+xnPvw3mvsM3gewr4XL0wLvsazlh2bfAG9nHA==; 24:rTt2ixnONN+ETjhpb+tsy5wflLXggOBQVfmQjEkpS/OIJU+WOXP3zABGgQSHJW1hiif1NbQwBeGGWPPkem5splc0SkdoJFDVV0fOW6lKkyQ=; 7:CYcoZo7hNPwxxa+FLjd4bHGmFv0pk1/R2OZwEK9X5kUueZqwcCENpZirIjNpBHtu95irtT2bvheKcDScC+/wa2XKnN3F5T7HmqR5jogxnOMnYpyQFW4hMLAI1saVW/8ABbTu3mA7b1Sszp6DuPer/+r8FHqrBT3nWkKd9PC2+lQShTlJVALdGycSCP1K/DxBuW76srmEVQ2X8rn8CzRz6jbRyI1TtPYH0dzltFfZLP0= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: maximintegrated.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 22 Sep 2017 20:13:14.2070 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: fbd909df-ea69-4788-a554-f24b7854ad03 X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN6PR11MB1857 To: unlisted-recipients:; (no To-header on input) Sender: linux-iio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 H. Kose Signed-off-by: Ismail H. Kose --- v6: * Removed reference resistor parsing v5: * Removed unused variable v4: * Removed unnecessary code and space optimization * Alphabetic order in Kconfig 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: * 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 drivers/iio/dac/Kconfig | 9 ++ drivers/iio/dac/Makefile | 1 + drivers/iio/dac/ds4424.c | 340 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 350 insertions(+) create mode 100644 drivers/iio/dac/ds4424.c 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..aea0cd12f9b8 --- /dev/null +++ b/drivers/iio/dac/ds4424.c @@ -0,0 +1,340 @@ +/* + * 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]; + 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, +}; + +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; + } + + 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");