Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757226AbcJ3TIK (ORCPT ); Sun, 30 Oct 2016 15:08:10 -0400 Received: from mail-he1eur01on0138.outbound.protection.outlook.com ([104.47.0.138]:63024 "EHLO EUR01-HE1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752586AbcJ3TIG (ORCPT ); Sun, 30 Oct 2016 15:08:06 -0400 X-Greylist: delayed 1902 seconds by postgrey-1.27 at vger.kernel.org; Sun, 30 Oct 2016 15:08:05 EDT Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=peda@axentia.se; Subject: Re: [PATCH v3 6/8] iio: dpot-dac: DAC driver based on a digital potentiometer To: Peter Meerwald-Stadler , Jonathan Cameron References: <1477262381-7800-1-git-send-email-peda@axentia.se> <1477262381-7800-7-git-send-email-peda@axentia.se> <301ab064-cd90-d99d-a05a-8a50ba759c62@kernel.org> CC: , Hartmut Knaack , Lars-Peter Clausen , Rob Herring , "Mark Rutland" , , From: Peter Rosin Organization: Axentia Technologies AB Message-ID: <48f793af-6f70-d666-0e9e-c170e607ab7e@axentia.se> Date: Sun, 30 Oct 2016 19:36:14 +0100 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Thunderbird/45.4.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset="windows-1252" Content-Transfer-Encoding: 7bit X-Originating-IP: [217.210.101.82] X-ClientProxiedBy: DB6PR0601CA0035.eurprd06.prod.outlook.com (10.169.209.21) To VI1PR0201MB2320.eurprd02.prod.outlook.com (10.168.63.22) X-MS-Office365-Filtering-Correlation-Id: 9c3a36ac-0dfe-4600-d5f4-08d400f3a4fb X-Microsoft-Exchange-Diagnostics: 1;VI1PR0201MB2320;2:gQ7SEyRDnFzZev9z+snH/A5Y4Gx+7/lvS3R89qEO8ypsyCTiNSz6ssK3Vb9fdmCJgjxk0isaK7jNwI7ox3CEQlazFHIb/twsd2rFECsbdTv7LPC82mjUUikIgnZBJaFkMNO0QTHZy3fD2+mTB884aKqdu8rM3WhCqziYNzl1GQQbc7ZWdFKtcyMNU+sDYgLaSsZ71mVIYG7XCZjdbAvUyw==;3:DZ3554OOG09BzWNxdcByVrk9x/d8FB2VNFAdmB6Fzy2YMb7r6VjkQYmUwMjFiEYejAxg4zxgDcnbMiHtCSteeycjq/DjsoKQEC6pRNmnOvaKle8ME81QPAoTfp+rmVW9nspwAvNUEVsBj/y2KOV8cw==;25:/JVC3REh7G6GK+35G1k/BozmAQVAPVDezbVMNZcft0EP6cz8C1PkBCpn1pucGRhaOFXrcOrMRFkJGpfT3F1nTdMqzpa4OM2jzvuoQO93KLndlVbK600RFivBqloYeelvbcNOcfMfoheXkVKJQz1/m8p2jLWD/gvWPTroD0vyOgEWbSM07BDUi6To7lyPPpTo9f3Tiz3q8GQJOAUZNskFVYJL5K7tsR2vRaMUn1qTsJ2Ry7uafCOHs3Nqqog3IYtMogmQ2QHZBqyooEu5TivZaQMyHFS4/m/HSPGmk2pOpWo8BjSVsb9wkfRKEVa1OAm7uxWoubWrnoYg/0DhbuaVf8QkVDuRFfaT4OGi1vGZytwBckbIKtbxM8vDareT/1Y/AHIlWWbeB9SliLHAH8G3bKQ4xvVUppvNaNvQ6z2Nis2eBjA8FvnLFILEKKYrWjP9 X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:VI1PR0201MB2320; X-Microsoft-Exchange-Diagnostics: 1;VI1PR0201MB2320;31:AORgYmJm5sYKpimHr397kgWYetCnEjQk8Q2qKTszXkEK+Pl5UYe/pAQKDTfY9Mw9JR9YXKnnD54VkvYw2MykidZMlTXQuQX+v8U9w0nRsDQtEcQz8gAmF5gtT6GltT/fP7KG2niETBEhUoZQ5d0XP5yBA2XuEx8rEAwG5eJZNsFKbPKInPtZms1Kys86cgMqJFzxztBJnAf5qzlqobS4t1CrP01Wci8J+a7arWo5eWnyaYCJJIEmPjcSN/UtWcPZ;4:4ve/xmEmlni+eO9X9Uz9Xtenj6VxtuA45g4AQW28HPyRjAmkoky6aXJRbLypb8QqG5aGH6wr+xL4TQaXV30j8+3gQPz02jFAXgjDaJYIqH9E5wATE8nXQDFB6wXwLTG3JfJrYCV7qsg/9NlG4e0J+dpzK21CAcmSHNWyDaRO2tQc6HJw4BNmvci/u0RU9C/MBQznvWpDwNs0kkM5F97lnFf/1/cdhZIPQKEXfD/WG9CH8H42Y/5pIvE23VuZ7C5XbLavK6ZsmCPFqXVg4SVDjeF+C/kY6WERC4dJPcBTf5o/v+r6oWWp0IaHqCYfAatQSk5Y+hwM1RhlSoOsmfRjwQLf3dFQ3W1YxK0fIO7CgQgHAU+Cso8kziQwO86+y1gUT2dwMqP133jLsyK+BW2VhyrRz88YswFhZXBv39LFvKbuGZuN4M3SiJW2nBWcm/GiN/9aWDZcoC+UN+UCRZXqAcmlzV5vfAW0Xh7LnvFa0Ug= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(9452136761055); X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(6040176)(601004)(2401047)(8121501046)(5005006)(3002001)(10201501046)(6042046)(6043046);SRVR:VI1PR0201MB2320;BCL:0;PCL:0;RULEID:;SRVR:VI1PR0201MB2320; X-Forefront-PRVS: 01110342A5 X-Forefront-Antispam-Report: SFV:NSPM;SFS:(10019020)(4630300001)(6049001)(6009001)(7916002)(52314003)(199003)(24454002)(50944005)(377424004)(189002)(83506001)(8666005)(7846002)(65956001)(101416001)(3846002)(6116002)(76176999)(50466002)(105586002)(66066001)(92566002)(81156014)(23746002)(65806001)(47776003)(8676002)(106356001)(7736002)(81166006)(50986999)(19580395003)(19580405001)(93886004)(117156001)(68736007)(54356999)(4326007)(86362001)(575784001)(42186005)(36756003)(33646002)(31686004)(31696002)(305945005)(586003)(6666003)(5660300001)(74482002)(65826007)(97736004)(2950100002)(5001770100001)(189998001)(4001150100001)(2906002)(230700001)(64126003)(77096005)(4001350100001)(556444002)(7059030)(2004002)(42262002);DIR:OUT;SFP:1102;SCL:1;SRVR:VI1PR0201MB2320;H:[192.168.0.125];FPR:;SPF:None;PTR:InfoNoRecords;A:1;MX:1;LANG:en; X-Microsoft-Exchange-Diagnostics: =?Windows-1252?Q?1;VI1PR0201MB2320;23:1t9NlALGTul4nnsJZiDnS/oBiCJKFub0zPl?= =?Windows-1252?Q?kt/ssrvJy8EfHzsuJD2NKKag2wRuWMg4vAr8ACgh2gDh7sru6Wyle1kk?= =?Windows-1252?Q?YPbUt231gScVezspQGIJM+BG+paddMX3R9R318LVbH+GdC64bActI/qD?= =?Windows-1252?Q?K8mF7BlDazMC6IbhGeTMtfubZzSJgHLEQ2f2PyJ9S4i6DwyjFCFoqgkO?= =?Windows-1252?Q?DnrpUMinSDSftqx1xfa3JgaTCn6dbYvmRXIzhnqKc4h8JASVmK7kwvqp?= =?Windows-1252?Q?3AERaODHG/Cz4+pxgtkII4/uvLufyWsPnkl4iFNGydndGdpwkTdkw93e?= =?Windows-1252?Q?7/WrpB9yISoZBht0mc4ESMZyqrg9w6ji4ytK0HNCOKmO1c1ekq3V2r6J?= =?Windows-1252?Q?0KHsDKK0P5JBZspp2cBPtp7LXkJ5rkvTFNCAC+AAxu3gzh1oXaxJgcSd?= =?Windows-1252?Q?uCCgABPzszQhyZrSd8t6yUkf87ArZ9v5eTid/IlP5ZKZ+uSdSIDzVHD0?= =?Windows-1252?Q?3+BTLd/ze0ZoGIfO7c00Jixoy4eoYteoGB2/o905YqBJeZ1V7Zt1eF9r?= =?Windows-1252?Q?tQS3CMy0dcVlZLTo2f2XVv+q1hEmVpqLkNnB7xN+XYIDcLXXe3uTYi/H?= =?Windows-1252?Q?rZ/sAUm9FbXRMcSTboM5NF9THGPIAd5TWCK2GBun1yqrLvWGGBYrO8ln?= =?Windows-1252?Q?qj38Yx/s3uIUBQCuIe4LaJ/l1pXPZzVntbY0J28oakz9PmyBfwqJSGiP?= =?Windows-1252?Q?CCD3b2NsivWUme9WOI71mAFg4bTgN8MlOvSNhlCc4DDdaJkMog7LiUmV?= =?Windows-1252?Q?W/vq/BkzQhPRJpTLlki5bVRmmmi5w4+LFIvS0ij51s2jLsizBmESdeQA?= =?Windows-1252?Q?/m/GmWVASwfFvzNMXtFH/9qbsrDaxQ/KSnCMbU97Xraqp0rfAOhvPzzf?= =?Windows-1252?Q?ObnHNMYBdcoCcF2Ve+knkGMiwV/w4nHX+cPe2/JWAsY0MV7kzr529Agz?= =?Windows-1252?Q?MSUIHPeDoqwucYHp9PuD3K/K5mpRe5rnx8vK2dCF0W79pCRLBslQjzeI?= =?Windows-1252?Q?Ikp6tGT9XXtcLMA/VGYeHRjbW8Y8M/a98bCLX5m5D0nn0VOJQSsWkdaC?= =?Windows-1252?Q?ibTGB8TX4HDPw1iBKgjVmJxuExo8epes6jI3iM4XC4kzFVgZihkETLdz?= =?Windows-1252?Q?XQlDmGxtGfj5yFTisJsmPdJd0PmDAyQXZfZNUkbXmD9Y8DHAn1epKPnM?= =?Windows-1252?Q?XveuzOhfk6yf2gyIgRDtqOrYu1oaMk3Mq/qaUQLBjbtKL3oW5A4dHxGt?= =?Windows-1252?Q?kyGRLprbw0IjYLFTfel1FYXST1LjOmFVQ3+SK72WXnM79txuVQIgwFCN?= =?Windows-1252?Q?0XWewOoFljwukxVUHLws+nGfGKF7wMZ0jSKYdKi8g3XfTmn9pq9ufR3u?= =?Windows-1252?Q?/nqEAIkCNoLOoJu2SaJglm9QRVtGNG6bzOgBNFgNY5j1PYgpUIogmc1Y?= =?Windows-1252?Q?rMrPUc8k5vipouPp9YTNlxJfrnGfwkHMNBp30BFBLGtPr2uqSi0nSoHD?= =?Windows-1252?Q?4OAahwC0XI00XDy9KIkoAv6HPCF21dnFyvsrrH5ZqLjCiPopSCAtq9JY?= =?Windows-1252?Q?BgeU8W+YBdQwGyLmDtPUtltePylIO+JBJCKvGsYw4RdrKaddSg2WwCs5?= =?Windows-1252?Q?5+UJEMUmtPw=3D=3D?= X-Microsoft-Exchange-Diagnostics: 1;VI1PR0201MB2320;6:oA1kRj8aZsgz74EtRcfE3n9LtLgJHa7PzldkWkRSeN+En2VA2yS/BuDGKdoR9SuVzxM667CgZWowYdC6cMRTTZBisyskq8T0dSR1XdzJvjIj39Y3VEmxSDCcjDgtHntsc/mYwZUwGz0la6PsXmUfkQHAwBV0IVLTn4/ZIWdmMXoLqTTgP0SeL5xSFeKol4siERbDZr1ejOXWiUj/UuHoowLTW9HPgS4CKLKp46Oz2HFoOlfHxLs5hjYTTjHX/nNSy0orKeINidMZLLJnq4LgfhiABsKIP6JemMMolg1jf1GNuXWPwG0rK0JUIQ4OXEJkFaGVB+yUJY3/BjSVNao6Ww==;5:m8UMO8PJQ+oqtjsnQpBCTvAT1amUXs/kYGG2f20fzOiGyiw94r7UbG7xIY5V223t7DOx7NeAFk2Hf9iEVKooN/gAQyd9CWsH/Z6gvG+eZTUiRrJ8ywDrAnbxXlW2kcP+9g50sZTHEVKYC8o6OiQneILj4ndrZ3FcWJVhx+w5sKw=;24:v/aK9GSBLvQYDXG5BkfhJy1UMiuSSGwKEFaMTLmpKT3H2EMvymZfJDlSHjF+/c/6g61NpauNu78mr/SASFJawhNVyOIlscYzXP2g/mbu+7w= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1;VI1PR0201MB2320;7:aiC8M3GHCbzhBt/b7sIE4EfdWxIEr9f1L7BbIxeTh68WbhysekMA6AaL1kQv9wK7oIOsAa4McFZxcxTzPzcTOKXRgfPTOqZSeA68/V1HLLfzG7w2jeSk1e0ISCQZlt8MgegPr92BZV3yXnI94Rd1k5rul7mlOJ4SWk7nIqG1j0srnSOIbxaAjUwSbnk+Qmi2g9aDRTPb6JAzdLYB2G9LbGfP3P4uxd4GkYDFEsPZ62MnY1KYayaGUrZ24b8cSzDf/zc/HTOzR0hQf0r34Jc8olQO2eH+RcfYwfq5OwMItRh8UrEKmanErWA7+5MQ+M/vyDn63T2IqVnIJmNPpUCpWm2d+Nc7smYEMGYQGvANnc0= X-OriginatorOrg: axentia.se X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Oct 2016 18:36:19.7381 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR0201MB2320 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 12482 Lines: 392 On 2016-10-30 16:32, Peter Meerwald-Stadler wrote: > On Sun, 30 Oct 2016, Jonathan Cameron wrote: > >> On 23/10/16 23:39, Peter Rosin wrote: >>> It is assumed that the dpot is used as a voltage divider between the >>> current dpot wiper setting and the maximum resistance of the dpot. The >>> divided voltage is provided by a vref regulator. >>> >>> .------. >>> .-----------. | | >>> | vref |--' .---. >>> | regulator |--. | | >>> '-----------' | | d | >>> | | p | >>> | | o | wiper >>> | | t |<---------+ >>> | | | >>> | '---' dac output voltage >>> | | >>> '------+------------+ >>> >>> Signed-off-by: Peter Rosin >> Only a trivial suggestion to drop the devinfo about max ohms now it's >> exposed (effectively) via the dpot driver. (really minor though so don't bother >> respinning for that!) >> >> Jonathan >>> --- >>> .../ABI/testing/sysfs-bus-iio-dac-dpot-dac | 8 + >>> MAINTAINERS | 2 + >>> drivers/iio/dac/Kconfig | 10 + >>> drivers/iio/dac/Makefile | 1 + >>> drivers/iio/dac/dpot-dac.c | 267 +++++++++++++++++++++ >>> 5 files changed, 288 insertions(+) >>> create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-dac-dpot-dac >>> create mode 100644 drivers/iio/dac/dpot-dac.c >>> >>> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-dac-dpot-dac b/Documentation/ABI/testing/sysfs-bus-iio-dac-dpot-dac >>> new file mode 100644 >>> index 000000000000..580e93f373f6 >>> --- /dev/null >>> +++ b/Documentation/ABI/testing/sysfs-bus-iio-dac-dpot-dac >>> @@ -0,0 +1,8 @@ >>> +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_raw_available >>> +Date: October 2016 >>> +KernelVersion: 4.9 >>> +Contact: Peter Rosin >>> +Description: >>> + The range of available values represented as the minimum value, >>> + the step and the maximum value, all enclosed in square brackets. >>> + Example: [0 1 256] >>> diff --git a/MAINTAINERS b/MAINTAINERS >>> index 6218010128dc..d7375f45ff0f 100644 >>> --- a/MAINTAINERS >>> +++ b/MAINTAINERS >>> @@ -6115,7 +6115,9 @@ IIO DIGITAL POTENTIOMETER DAC >>> M: Peter Rosin >>> L: linux-iio@vger.kernel.org >>> S: Maintained >>> +F: Documentation/ABI/testing/sysfs-bus-iio-dac-dpot-dac >>> F: Documentation/devicetree/bindings/iio/dac/dpot-dac.txt >>> +F: drivers/iio/dac/dpot-dac.c >>> >>> IIO SUBSYSTEM AND DRIVERS >>> M: Jonathan Cameron >>> diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig >>> index 120b24478469..d3084028905b 100644 >>> --- a/drivers/iio/dac/Kconfig >>> +++ b/drivers/iio/dac/Kconfig >>> @@ -200,6 +200,16 @@ config AD8801 >>> To compile this driver as a module choose M here: the module will be called >>> ad8801. >>> >>> +config DPOT_DAC >>> + tristate "DAC emulation using a DPOT" >>> + depends on OF >>> + help >>> + Say yes here to build support for DAC emulation using a digital >>> + potentiometer. >>> + >>> + To compile this driver as a module, choose M here: the module will be >>> + called dpot-dac. >>> + >>> config LPC18XX_DAC >>> tristate "NXP LPC18xx DAC driver" >>> depends on ARCH_LPC18XX || COMPILE_TEST >>> diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile >>> index 27642bbf75f2..f01bf4a99867 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_DPOT_DAC) += dpot-dac.o >>> obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o >>> obj-$(CONFIG_M62332) += m62332.o >>> obj-$(CONFIG_MAX517) += max517.o >>> diff --git a/drivers/iio/dac/dpot-dac.c b/drivers/iio/dac/dpot-dac.c >>> new file mode 100644 >>> index 000000000000..f227a211d34d >>> --- /dev/null >>> +++ b/drivers/iio/dac/dpot-dac.c >>> @@ -0,0 +1,267 @@ >>> +/* >>> + * IIO DAC emulation driver using a digital potentiometer >>> + * >>> + * Copyright (C) 2016 Axentia Technologies AB >>> + * >>> + * Author: Peter Rosin >>> + * >>> + * 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. >>> + */ >>> + >>> +/* >>> + * It is assumed that the dpot is used as a voltage divider between the >>> + * current dpot wiper setting and the maximum resistance of the dpot. The >>> + * divided voltage is provided by a vref regulator. >>> + * >>> + * .------. >>> + * .-----------. | | >>> + * | vref |--' .---. >>> + * | regulator |--. | | >>> + * '-----------' | | d | >>> + * | | p | >>> + * | | o | wiper >>> + * | | t |<---------+ >>> + * | | | >>> + * | '---' dac output voltage >>> + * | | >>> + * '------+------------+ >>> + */ >>> + >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> + >>> +struct dpot_dac { >>> + struct regulator *vref; >>> + struct iio_channel *dpot; >>> + u32 max_ohms; >>> +}; >>> + >>> +static const struct iio_chan_spec dpot_dac_iio_channel = { >>> + .type = IIO_VOLTAGE, >>> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) >>> + | BIT(IIO_CHAN_INFO_SCALE), >>> + .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW), >>> + .output = 1, >>> + .indexed = 1, >>> +}; >>> + >>> +static int dpot_dac_read_raw(struct iio_dev *indio_dev, >>> + struct iio_chan_spec const *chan, >>> + int *val, int *val2, long mask) >>> +{ >>> + struct dpot_dac *dac = iio_priv(indio_dev); >>> + int ret; >>> + unsigned long long tmp; >>> + >>> + switch (mask) { >>> + case IIO_CHAN_INFO_RAW: >>> + return iio_read_channel_raw(dac->dpot, val); >>> + >>> + case IIO_CHAN_INFO_SCALE: >>> + ret = iio_read_channel_scale(dac->dpot, val, val2); >>> + switch (ret) { >>> + case IIO_VAL_FRACTIONAL_LOG2: >>> + tmp = *val * 1000000000LL; >>> + do_div(tmp, dac->max_ohms); >>> + tmp *= regulator_get_voltage(dac->vref) / 1000; >>> + do_div(tmp, 1000000000LL); >>> + *val = tmp; >>> + return ret; >>> + case IIO_VAL_INT: >>> + /* >>> + * Convert integer scale to fractional scale by >>> + * setting the denominator (val2) to one... >>> + */ >>> + *val2 = 1; >>> + ret = IIO_VAL_FRACTIONAL; >>> + /* ...and fall through. */ >>> + case IIO_VAL_FRACTIONAL: >>> + *val *= regulator_get_voltage(dac->vref) / 1000; >>> + *val2 *= dac->max_ohms; >>> + break; >>> + } >>> + >>> + return ret; >>> + } >>> + >>> + return -EINVAL; >>> +} >>> + >>> +static int dpot_dac_read_avail(struct iio_dev *indio_dev, >>> + struct iio_chan_spec const *chan, >>> + const int **vals, int *type, int *length, >>> + long mask) >>> +{ >>> + struct dpot_dac *dac = iio_priv(indio_dev); >>> + >>> + switch (mask) { >>> + case IIO_CHAN_INFO_RAW: >>> + return iio_read_avail_channel_raw(dac->dpot, >>> + vals, type, length); >>> + } >>> + >>> + return -EINVAL; >>> +} >>> + >>> +static int dpot_dac_write_raw(struct iio_dev *indio_dev, >>> + struct iio_chan_spec const *chan, >>> + int val, int val2, long mask) >>> +{ >>> + struct dpot_dac *dac = iio_priv(indio_dev); >>> + >>> + switch (mask) { >>> + case IIO_CHAN_INFO_RAW: >>> + return iio_write_channel_raw(dac->dpot, val); >>> + } >>> + >>> + return -EINVAL; >>> +} >>> + >>> +static const struct iio_info dpot_dac_info = { >>> + .read_raw = dpot_dac_read_raw, >>> + .read_avail = dpot_dac_read_avail, >>> + .write_raw = dpot_dac_write_raw, >>> + .driver_module = THIS_MODULE, >>> +}; >>> + >>> +static int dpot_dac_channel_max_ohms(struct iio_dev *indio_dev) >>> +{ >>> + struct device *dev = &indio_dev->dev; >>> + struct dpot_dac *dac = iio_priv(indio_dev); >>> + unsigned long long tmp; >>> + int ret; >>> + int val; >>> + int val2; >>> + int max; >>> + >>> + ret = iio_read_max_channel_raw(dac->dpot, &max); >>> + if (ret < 0) { >>> + dev_err(dev, "dpot does not indicate its raw maximum value\n"); >>> + return ret; >>> + } >>> + >>> + switch (iio_read_channel_scale(dac->dpot, &val, &val2)) { >>> + case IIO_VAL_INT: >>> + return max * val; >>> + case IIO_VAL_FRACTIONAL: >>> + tmp = (unsigned long long)max * val; >>> + do_div(tmp, val2); >>> + return tmp; >>> + case IIO_VAL_FRACTIONAL_LOG2: >>> + tmp = (s64)val * 1000000000LL * max >> val2; > > (s64) necessary? > or rather unsigned long long? Fuck it, I'll just remove that case completely. I don't care about weird fractional-log2-shit that'll probably overflow anyway. Happy? >>> + do_div(tmp, 1000000000LL); >>> + return tmp; >>> + default: >>> + dev_err(dev, "dpot has a scale that is too weird\n"); >>> + } >>> + >>> + return -EINVAL; >>> +} >>> + >>> +static int dpot_dac_probe(struct platform_device *pdev) >>> +{ >>> + struct device *dev = &pdev->dev; >>> + struct iio_dev *indio_dev; >>> + struct dpot_dac *dac; >>> + enum iio_chan_type type; >>> + int ret; >>> + >>> + indio_dev = devm_iio_device_alloc(dev, sizeof(*dac)); >>> + if (!indio_dev) >>> + return -ENOMEM; >>> + >>> + platform_set_drvdata(pdev, indio_dev); >>> + dac = iio_priv(indio_dev); >>> + >>> + indio_dev->name = dev_name(dev); >>> + indio_dev->dev.parent = dev; >>> + indio_dev->info = &dpot_dac_info; >>> + indio_dev->modes = INDIO_DIRECT_MODE; >>> + indio_dev->channels = &dpot_dac_iio_channel; >>> + indio_dev->num_channels = 1; >>> + >>> + dac->vref = devm_regulator_get(dev, "vref"); >>> + if (IS_ERR(dac->vref)) { >>> + if (PTR_ERR(dac->dpot) != -EPROBE_DEFER) >>> + dev_err(&pdev->dev, "failed to get vref regulator\n"); >>> + return PTR_ERR(dac->vref); >>> + } >>> + >>> + dac->dpot = devm_iio_channel_get(dev, "dpot"); >>> + if (IS_ERR(dac->dpot)) { >>> + if (PTR_ERR(dac->dpot) != -EPROBE_DEFER) >>> + dev_err(dev, "failed to get dpot input channel\n"); >>> + return PTR_ERR(dac->dpot); >>> + } >>> + >>> + ret = iio_get_channel_type(dac->dpot, &type); >>> + if (ret < 0) >>> + return ret; >>> + >>> + if (type != IIO_RESISTANCE) { >>> + dev_err(dev, "dpot is of the wrong type\n"); >>> + return -EINVAL; >>> + } >>> + >>> + ret = dpot_dac_channel_max_ohms(indio_dev); >>> + if (ret < 0) >>> + return ret; >>> + dac->max_ohms = ret; >>> + dev_info(dev, "dpot max is %d\n", dac->max_ohms); >> Given we can query this (indirectly) from the dpot itself, I'd drop this now. > > max_ohms is u32, so this should be %u not %d? You're right, but that dev_info is about to be killed anyway, as requested by Jonathan. Cheers, Peter >> >>> + >>> + ret = regulator_enable(dac->vref); >>> + if (ret) { >>> + dev_err(dev, "failed to enable the vref regulator\n"); >>> + return ret; >>> + } >>> + >>> + ret = iio_device_register(indio_dev); >>> + if (ret) { >>> + dev_err(dev, "failed to register iio device\n"); >>> + goto disable_reg; >>> + } >>> + >>> + return 0; >>> + >>> +disable_reg: >>> + regulator_disable(dac->vref); >>> + return ret; >>> +} >>> + >>> +static int dpot_dac_remove(struct platform_device *pdev) >>> +{ >>> + struct iio_dev *indio_dev = platform_get_drvdata(pdev); >>> + struct dpot_dac *dac = iio_priv(indio_dev); >>> + >>> + iio_device_unregister(indio_dev); >>> + regulator_disable(dac->vref); >>> + >>> + return 0; >>> +} >>> + >>> +static const struct of_device_id dpot_dac_match[] = { >>> + { .compatible = "dpot-dac" }, >>> + { /* sentinel */ } >>> +}; >>> +MODULE_DEVICE_TABLE(of, dpot_dac_match); >>> + >>> +static struct platform_driver dpot_dac_driver = { >>> + .probe = dpot_dac_probe, >>> + .remove = dpot_dac_remove, >>> + .driver = { >>> + .name = "iio-dpot-dac", >>> + .of_match_table = dpot_dac_match, >>> + }, >>> +}; >>> +module_platform_driver(dpot_dac_driver); >>> + >>> +MODULE_DESCRIPTION("DAC emulation driver using a digital potentiometer"); >>> +MODULE_AUTHOR("Peter Rosin "); >>> +MODULE_LICENSE("GPL v2"); >>> >> >