From patchwork Tue Sep 19 07:23:32 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ismail Kose X-Patchwork-Id: 9958351 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 9F4B760208 for ; Tue, 19 Sep 2017 07:24:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C3BEC28CF4 for ; Tue, 19 Sep 2017 07:24:31 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B85FC28D00; Tue, 19 Sep 2017 07:24:31 +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 AE99128CFF for ; Tue, 19 Sep 2017 07:24:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751390AbdISHY3 (ORCPT ); Tue, 19 Sep 2017 03:24:29 -0400 Received: from mail-bl2nam02on0133.outbound.protection.outlook.com ([104.47.38.133]:23575 "EHLO NAM02-BL2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751009AbdISHY1 (ORCPT ); Tue, 19 Sep 2017 03:24:27 -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=5SEqAHCtpoubY3a7WwFg3b3e2n3F0gq/BQ60WHBPglk=; b=mo4tYrR6DVNJPhzf7xHPcl+Kbz8wXuRP2HIkXmvBm11ILaogHosEy1Phs/k+cqISZJ6rrs5K/0S4+Um+AJNUcEUJWV4WWObs9yPrdNeD7Y6XcTXQrKFwsyM/jeH4cf5KqYYqnAPzyg7OPYBaZabNeOxwZlc7xOntgP+LiXzaTwI= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Ismail.Kose@maximintegrated.com; Received: from kose.maxim-ic.com (204.17.143.20) by CY4PR11MB1863.namprd11.prod.outlook.com (10.175.61.137) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.56.11; Tue, 19 Sep 2017 07:24:22 +0000 From: Ismail Kose Cc: "Ismail H. Kose" , Jonathan Cameron , Hartmut Knaack , Lars-Peter Clausen , Peter Meerwald-Stadler , Rob Herring , Mark Rutland , Peter Rosin , Maxime Roussin-Belanger , Jean-Francois Dagenais , Fabrice Gasnier , Mike Looijmans , linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v5] iio: dac: ds4422/ds4424 dac driver Date: Tue, 19 Sep 2017 00:23:32 -0700 Message-Id: <20170919072341.10249-1-Ismail.Kose@maximintegrated.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: References: MIME-Version: 1.0 X-Originating-IP: [204.17.143.20] X-ClientProxiedBy: YQXPR0101CA0058.CANPRD01.PROD.OUTLOOK.COM (52.132.74.35) To CY4PR11MB1863.namprd11.prod.outlook.com (10.175.61.137) X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 2fc10ef4-5a2b-4acd-b2b2-08d4ff2f747e X-MS-Office365-Filtering-HT: Tenant X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(300000500095)(300135000095)(300000501095)(300135300095)(22001)(300000502095)(300135100095)(2017030254152)(300000503095)(300135400095)(48565401081)(2017052603199)(201703131423075)(201703031133081)(201702281549075)(300000504095)(300135200095)(300000505095)(300135600095)(300000506095)(300135500095); SRVR:CY4PR11MB1863; X-Microsoft-Exchange-Diagnostics: 1; CY4PR11MB1863; 3:Dvvl7zSzc8fnz3lGG/cXmagsYJ4ntN7a4XDSsS19AewdkXk/h7p87I3LkxZL99neLwUtQn0TRienqBLfg8HNEg5O3/NI9qPmCmyyMAdYIm1HKYrMRMewGY+SYcFNziusTonrSYiL3/b46hLndYqdhigWG/TNvkVlGB992DVvGYTwKE9bZl1KkzMPijyTUodR20xprQo/ORHPXJow7/e3rJ0EdDcfrBt8JcQDqI98fGDZh72XKMYSr8E8kKe3/0To; 25:MXJLrEVXBDGuU1pOiDt0e2+ufrWRlAHQCs5xp4zAzQXS9a6BhTyDvB+S9nByvAYyc9f8BOMFi+diY1CMrR79C8f0HllG3jCdc32gpoZF3C9j0yqjDCAvYOB1W0orvW+qzAeZsvIdWRBNqGhsVqI49ez7Aw75NoKTbauREDB/sEVG4Oz+j48fK+KGCX2thX+tJXpxLqf3ar6MoU8/TobEA3tLZmUkf+Pnh+mel6ZhegV1GRYWS53QKH/kaTWKVud/dLqRKEVqaS/EQyCoARF4dd2Bu79Hp145mmlDG3QcOexWygUNr8R78qljLz64KHo7e0h4vUVAss0dJRatpggCPQ==; 31:WF/8GkJcULfPXplTMTLPd+pTHDxpUIwr5f4RtI/utqkGls3OTj+v1bqkenQJ9t+buTwUgQL3ZI6lcxMHR5wfcjghZBTdi9D3j5QqtAGL3kmiuU7FaRO25a7TgJXc18UuOqvbKTwGtSl/XObeTc71aW1udFjprm1SF+UHjWk8QFPOLn673oiYUb3MOBuFsWzNlS2cMwRoaOpB97jDHLmFwfBCvRa51Q9MGSkA2ro5MeI= X-MS-TrafficTypeDiagnostic: CY4PR11MB1863: X-Microsoft-Exchange-Diagnostics: 1; CY4PR11MB1863; 20:5A8O5fypYtgxAAWy+5wR9AlQc1Bm1tTD8LDmmz1esJh7FvKCrHNMiyQ3qe336j0mLK9vg3JvuLJOvoUEw/kqLihodEC4BVWyO0H6zJG9WsExbHiSJkR1wHME3/ZteVhsWOEVZl+CtT/91zsHe1H+y+1Do9XcQXdq+E4lYEvSHuR9XXTY5sMAF6jjT+F1PHGfInEaCGwe8V4g6n8cZrRvLVtLc+pYOjjWvDvL6r/b0vrr8jdc4zBaM1cpfEmEukwqK1zR57cBmA/WVETwOMjQZMkxsK8Sbj8/6eLFJc74VyLlkESOMz4ZQREorub11Aa0ne0lMOsnArJGcPqryDgj8gCb7ctfsNiG9nqzWFa0kJ1xUFYZs2csPZIzVsuZg4B8QIv4yMDGL0cMHkotQoEJ0nrYnStzQaRxTF2mwqEwTM10sc6ugmvJ9Y1HVQh5ccb2pVzJ+NOc3uG0Zfx+wiTmI1YJcPtcqLN1vV/HzceTb2Ea79Zw6+5X/zcPM2Oiit2H; 4:L4JAKICiZiaaHea1e7oqKFygt+1m2fCLWPrRLu8QaGcczgA/S73fqlOZq60UR7/Y/t2FuGG1aeMbsVF9p3PGwelqr+COBmmoHxhVlJGUZJzUMshxm32P9yRkM49dZ2gctc/VVy/E/tX0cyA9mKGEFOTAvAn0puPLnElwtcpzzt2rWPdY9nn9PNxIgR9msudcYIL5+5hXdZ/4oSd1HTrNCZL7yTXVRIHgY45TRh5u0SrXtG3NM+5bhGKN8zvxXX4G+18VdoS0U4F0ZcEYLsmxdzyHIz9igyIQKjRCyrcu+Ik= 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)(20161123564025)(20161123560025)(20161123558100)(201703131423075)(201702281528075)(201703061421075)(201703061406153)(6072148)(201708071742011)(100000704101)(100105200095)(100000705101)(100105500095); SRVR:CY4PR11MB1863; BCL:0; PCL:0; RULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(100000804101)(100110200095)(100000805101)(100110500095); SRVR:CY4PR11MB1863; X-Forefront-PRVS: 04359FAD81 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(6009001)(39860400002)(346002)(376002)(189002)(199003)(48376002)(1671002)(50466002)(4326008)(25786009)(69596002)(478600001)(72206003)(189998001)(2906002)(76176999)(316002)(16526017)(6666003)(6506006)(86362001)(16586007)(6486002)(36756003)(50986999)(97736004)(2950100002)(8936002)(81166006)(101416001)(50226002)(105586002)(106356001)(1076002)(81156014)(8676002)(305945005)(7736002)(7416002)(5660300001)(53416004)(3846002)(6116002)(5003940100001)(39060400002)(53936002)(68736007)(47776003)(6512007)(109986005)(54906002)(8666007)(6306002)(66066001)(266003)(2004002); DIR:OUT; SFP:1102; SCL:1; SRVR:CY4PR11MB1863; 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; CY4PR11MB1863; 23:ZBkniwVEEvAH95c1wsH7dqt6pew7zEtYbvyTqfk87?= =?us-ascii?Q?Ugr0K/aDBVmxIRbfjoL1qsmuzmkCmiNtmZV5xOrFW8CAHipAIdyx1QdfFmoP?= =?us-ascii?Q?vDnPCm6V5H9SKYX9Qe4Y4/gdT2ofoQqp0ANEWW/lPrLKsoOSU5zh0e3kfY1n?= =?us-ascii?Q?fMQzwlOymFNHmdwxSj1CXDbHid5OvHXuaMW43OS2RXB/U9nXnMuA8PydggbQ?= =?us-ascii?Q?XPblCSgz2cBgOit7AgNKW2tXw4j6EruV6dEt2vG9/cTpoQ22Z6a4xWzVptSI?= =?us-ascii?Q?VzwEBrz581XBc/Qp5o+2l+X7JZha9KoYMQpriz2lxVtELNKrRIMEPL1cVjSa?= =?us-ascii?Q?koI/pn53bTl1BfvbBkhygbEXi1Cklc153KPt7cQFuy7gz1eTfnQkto5cZa6k?= =?us-ascii?Q?b4lZpoKCTRh0P9v974racsrVTRx8gCB7hgVT5fDXWiAFkIv7jlmmrGZjEy5G?= =?us-ascii?Q?wW8VB/Ajh472NTTq6yQ/OIZgGu4Ed93r78Pp0MT6Iqca2Z+Sssq+g3r03oMz?= =?us-ascii?Q?DxPgdaGj+p5OY52o+MkLCxlfyI4kr03yJHjSYJzzRabZ2pusWMycYFvfne9c?= =?us-ascii?Q?tJOFGJnkUWgWamqDdf0HyMFVIDkhZoTGjs2qae8SRM3chS5vkdOgc1zH4gE5?= =?us-ascii?Q?EDY+ODgoU8Fv2N96dnDyc7RWpJzPOalotrAg31cUilO0zFaxj4LDZmG9DLUV?= =?us-ascii?Q?3KgZF+nr96VESELKpwSuKYfc0WMl8aUkGJtU3irqBQcH+VRCOP8jPgd3Pvzm?= =?us-ascii?Q?XD+kOp4NwGKui8fXFBgRE7vdI+3ylMhgUWg502fj+9BI3c+yoJwhvzL/oXIV?= =?us-ascii?Q?VFO5kceDU5tl9BbHSgvqh9aeyNPdZnfLse93tJMpiVxCCNxnYU0gjJBj8H7q?= =?us-ascii?Q?D2RcizAFgpjlvj4A/vctT39aLmqQWR4iBcbjYLOYGlkWARD+Ylx7Kyed6hvS?= =?us-ascii?Q?SxNeuT+ih9S624Xnw0RFjhUnmEGUPtrlQgTZQuR+OLQGiVWFQ8FlStYloKoM?= =?us-ascii?Q?UaNQF6ssz/WJWdvAdeU9CuHEi7FgIwv8lMg5smNU+bmVh2vpjOBEvM+WnHyh?= =?us-ascii?Q?xLMjBWjkbAN9sEqgDguZJhbhnHJcjHmrA8InWg8rc3xS4I7LvLuHwTv5J+nM?= =?us-ascii?Q?wHTRdxVpjukn+jqZGpxrmssw8uGBT5UHlSNH6tIid4kSjMJqWAUOnori0Yg1?= =?us-ascii?Q?YniXdXFB+aH+2mQWNhgwyZM3bvVBZJyypslMSKyLdT3GGrYhi40N/ZAVXJoN?= =?us-ascii?Q?ovlXajOIud2/OvBHBnmV/qDDLESAkoLQlmuKGB34KJm4QNVlYWzfWmYaj2tA?= =?us-ascii?Q?O039EEVzBX1cMVovYnbKC8=3D?= X-Microsoft-Exchange-Diagnostics: 1; CY4PR11MB1863; 6:nWphxB6hCVi3zZhY2aj58e1oOURMtqP+Mtl0jb7yPk/V8YHSbm0janoMx/Muks/r4eUVc0jGAc80frikjANdAwvp7LP8Pduo9VirH/6iIkcyCiAEjTKqATLKvLORXSuLA1TNNkI6v5VafDQR0NM/LNyjPzD6yZ1LmTWWxKpPEsRGIHzFcCF5JWd4WMJLgJ8OCYkqK2ztc+Ldp5QR7xbv92h1xt16sdyJ+KyWhYU1Gu8ftLwtf/Zdx8KL5C0uTyT9EbyK+5kf4aSMZOTW/c6ZhulzkaynWbqy5S3dnYIoCBnfVAzHHQbF8ckimrcjmFPhZD1MHxmEhvAqH0Dv3Z9Xag==; 5:dXsiNDoFJCnj+Ieud/EL3m6fln9c54DjWPoXXslhTDircInDJQaeDQX3IVKF0rTu8PXd9qy38Hoo3ervPYEuui++SMBwq0o+VXkEJPj5jrkRq7wyIwuW+FjkheUe/DW7jOdw8AWNh2lZQBUqpK2jRA==; 24:ZKLInaqmlphNFkKbSZpOwmb9eWUp3uqgkXPsRZWT2FeT0jnNsw29Ev6a2RzbQXdSPj2CSUNTsJBGXVHxeKQzAActc/h7gCni8om6KVVcDOk=; 7:IyLuwUh4dt8qa3r/6wXij4QvGXCs4xit8iS74TOk1p7c+4o71yeO5ixg9Ff/ITW1Z9dMgUo7DcC2WJroyrmahJ+lYLT3l76R59ykpC11FNUOZF7TPBp2yqkZL+1zW/CS8pt4HJT2uMBFo1sRVhMtAx47RQsnuZ44Bb1Q8ou+8cIZphK9L+W30/wMTktBWvAh4OcWnCdVqbD01JiMoYvs9XBMh16OT9zKDJ1mdIF/pvI= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: maximintegrated.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 19 Sep 2017 07:24:22.6830 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: fbd909df-ea69-4788-a554-f24b7854ad03 X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY4PR11MB1863 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 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 --- v5: * Removed unused variable 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: * 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 | 394 +++++++++++++++++++++ 4 files changed, 424 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..27a3681e1869 --- /dev/null +++ b/drivers/iio/dac/ds4424.c @@ -0,0 +1,394 @@ +/* + * 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; + 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");