Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755424AbdC2Jl7 (ORCPT ); Wed, 29 Mar 2017 05:41:59 -0400 Received: from mail-bl2nam02on0053.outbound.protection.outlook.com ([104.47.38.53]:42767 "EHLO NAM02-BL2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1755033AbdC2Jlv (ORCPT ); Wed, 29 Mar 2017 05:41:51 -0400 Authentication-Results: spf=pass (sender IP is 137.71.25.57) smtp.mailfrom=analog.com; vger.kernel.org; dkim=none (message not signed) header.d=none;vger.kernel.org; dmarc=bestguesspass action=none header.from=analog.com; From: To: , , , , , CC: , , , Michael Hennerich Subject: [PATCH v3] iio:adc: Driver for Linear Technology LTC2497 ADC Date: Wed, 29 Mar 2017 11:42:58 +0200 Message-ID: <1490780578-2468-1-git-send-email-michael.hennerich@analog.com> X-Mailer: git-send-email 2.7.4 MIME-Version: 1.0 Content-Type: text/plain X-EOPAttributedMessage: 0 X-MS-Office365-Filtering-HT: Tenant X-Forefront-Antispam-Report: CIP:137.71.25.57;IPV:NLI;CTRY:US;EFV:NLI;SFV:NSPM;SFS:(10009020)(6009001)(39850400002)(39410400002)(39400400002)(39450400003)(39840400002)(39860400002)(2980300002)(438002)(189002)(199003)(1720100001)(50226002)(47776003)(6306002)(4326008)(8666007)(6666003)(8936002)(2906002)(33646002)(2876002)(8676002)(50986999)(36756003)(5660300001)(107886003)(966004)(38730400002)(2201001)(86362001)(7636002)(86152003)(356003)(50466002)(48376002)(305945005)(189998001)(106466001)(77096006)(5003940100001)(562404015);DIR:OUT;SFP:1101;SCL:1;SRVR:SN1PR0301MB1550;H:nwd2mta2.analog.com;FPR:;SPF:Pass;MLV:sfv;MX:1;A:1;LANG:en; X-Microsoft-Exchange-Diagnostics: 1;BL2FFO11FD040;1:SNHF2+kp20g+vcrPOv5n3pLpBKnWpHJy25149JeC3aUIa4xv3x3G3VWTY293RbI5AKGkAyEA9+AMQms0HOFoIOmfrGuk2smq27RPesiikuNcRzy157u7nRQ06Ztp0cDBEnCbVcVflycK17FkaObBXeIak4s3Lm2Tuk3/N7LdYY4uPMw6lhk+mFgXv/Twy2DCVyIDoXTt9a3UoGqcU9SYYXVTDoZyxIwFK8EqlwRxfY3yqZ4FX9NpImj3supK/VupbgJ6q3sMenBs9KQjunk7vagHCJkqN5R/9RnJTieae9LYtHi7WqCJ7mCJvgEgocLgCC//rh0EK+ZIrXvxkA5FSj8IXmucwZHUBQ6nkDR0XHCuq+rytm8VMP0u9n29g8a65/Ohc8YQ1BwrUJkBapOwxrfeQJe0Aa1R6/Vc6MaBxGbNwe/+Izzq7Gw683XnHNF3uhrOSNK/ZG47/X5x9zjRBo2YIfhvnX5rgpjielDNJ0nWDInJxsGS/T+/iKBzIOBoTospzqqIl/mG/6o98hSOd7c2W/wJ6moOz7k1/Za9nkE6lPBC+GO247dSVZXwNL5RLIsQHGj5duAaRUPLSlZX7VkjA5h/uhgepnugOKe9F+P7IBmedec9yXlNa64v8eyP X-MS-Office365-Filtering-Correlation-Id: 4d55a078-e5ee-4933-8cfb-08d47687ce63 X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:(22001)(8251501002)(2017030254075)(201703131423074)(201703031133080);SRVR:SN1PR0301MB1550; X-Microsoft-Exchange-Diagnostics: 1;SN1PR0301MB1550;3:4lu5OhI82tlLHisEWi7gIeBAY/Qnk5uSH5c+0OTmHnsdM6S96ktoW1sa/iv/bky0FJYck3j982JaEafWgktS9eKalVLKsn7aBxPl6OF76q9z8x6Jz9yszDPRbWTlMacNJHwZ06PY2EfOBYRjuuf5rCgzlXlzyXpLH5CGuCU+yXO48eS7W814AtzSdiyCB+usn9vHU1lgUe4SkUYzGVRnriLpDOOho0KbMCTxgSejwaIlHiBO5Ga4uhwHze0hLlTYL72eu8ls8EZbeH/4ybOGRoglrj2xlCD+ZnqtQbl2S/VtsvSgKXYX8xNPY2JX/c+ATZXCuKNNdoheuJumB0vq3fp4MNI5raQmopOFc2Z5xJReiixfkj8EOsOL6sEzu0Onlpbf+CwJFSnc8kM9OAI1sE1saLAGDP3drfeALGnVdrrssTSbS7zSMyDCt2cnP0kWMhKp0lCdXAJPzOshLobdlzSI2UjvsalXPEZ3KTN8ZbIpjPp5q6xWxaUNpwHZQj7m X-Microsoft-Exchange-Diagnostics: 1;SN1PR0301MB1550;25:WqrBW8dLJ8P+oeyjo+VDaW7iRtI5AFABrbLMgF5F8d9rsdUC7kEKGRAAOCJEKQgDpEv1rO9XaRgPPXfY9Bts6DRoEhcuJXEDpZPPPeMDjQjqWrnIESScaNieGXs6v7Rd3cHusCzStCqbg6D/OggnLSk/wlQLKH3yqA52SvirBrVlelovCRQPLmEp3bKWMA0P6meNZ+/J2KSjLfaxlOXaBg/X4efojd7bDhNHklQoWeXSRQnlxy+WfFvfx2i4HgHCz2AGFhWpnjNaMNnUY3b6t8v/LqFi/MsZGOVFIImo3pobiALlWqBP/UUpipip3tcxTSvs5RZwl3POnrq/9yTDO1y/DpC97ULgX8S5I0EwShge6UD55ogHX2lF7Y6A6Ykn1mS6FLtVgGUI1I1YSGbylOh3MLJ6ArCIfu1WF5hLb57kqu9YI6sJLuObCZ48sz+mWPxBH3pi4/M14TQk/eKx7Q==;31:EnUQq4SIyS1hnpQ8RS0l+l2l/grsGXw/HIX+6QU5Kn8aNYJlGSUaVGh229FxDANka/VuWu6Efm5GFoHNWxJqKd73rgHKeTEdyPRXffFirgC6v4toAYLnZkgOrH6x5BxOxQWjwlYgRUIvcpvsCFSXDC7da8TeYVNomb1vjqKZ+TJNIXJfcALTNaPCKQBSMDEwS4fVq+Yn2B7JA5vgxFd9iz8CAgstTNUimFy4Pqislhyxk0I3agwN/xuXXOlKz5Aj7TJDvoZBm1HwgdS3E5OvXvhsOKCDsbbPDP2dHHIiI6w= X-Microsoft-Exchange-Diagnostics: 1;SN1PR0301MB1550;20:RC+tgwZFLkwOynSK06apYVqtixMG+FuPM8ZOJQKXgLzM/rcIDVWTnsqQ18fwb7KcEX1vZniGZPQhJnVi93xlGOYxTr1rvgJDfSGbO4YpJlHOqtNleP19eNjYiOPWs25J/4HNYjyKf/BuFHjJdvER/4NAwXVs50ADSbhbrIWlMnL+dPmEqwG1EY2C6p48MVPrpxaC5cCIC4S0qj47Iua0bK8AzsEk5vUZ2BFebWm9f6ffB1PX9CRXIkMbGwUn+LNsQjqy/JrW/O564fA4qWa1t895rWutAd8EZtnzDanM09WbbsVGTmhwyfY7wYicSoeUcJ2ZCdVTdxD9pbT50P7cIoq4O7O8TKLtCTPvwm7pyL5wZc6okyKrHlDxQJSt4VtKTZf55iAOCjKyYaDfTNWuHjNIiwY1aiLYLG1yDltc23bRhN1WtUu/b7qtOLTlPggEtx1RpwA6BXSq9eVKZeU0iKW2diCRgyMd6rQmk8KOeaezNvUOwCf9BietNNKbDBa5 X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(232431446821674)(170811661138872); X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(6040449)(601004)(2401047)(13018025)(13024025)(13017025)(5005006)(8121501046)(13015025)(13023025)(3002001)(10201501046)(6055026)(6041248)(20161123562025)(20161123555025)(20161123558025)(20161123560025)(201703131423074)(201702281528074)(201703061421074)(201703061406074)(20161123564025)(6072148);SRVR:SN1PR0301MB1550;BCL:0;PCL:0;RULEID:;SRVR:SN1PR0301MB1550; X-Microsoft-Exchange-Diagnostics: 1;SN1PR0301MB1550;4:3DQ9WPkN0GxCUHcJxg34bXY9pMHYDNWDMP5Yky807DzkiRcYYuW411JeL7jAcK5BGb7XkWQrQyfMZTqUSMSNOU0p0igt1AXmFP4jv7atcgZ/MyfTPH+Lqfv3z83a/FcFBh43XX+pod/zGsrVp8WXy06Bx/Hh11PoTH0yTnrU81RT/XlcVxp/QV0wS+aYvOYf2mI39cR2WSvdwa+NkG7PTgOTKO9moUb5bxzmO7CMi3rGyafuyJ1uzH8pKN9GSngxssNUY9PWE1/CkefgtHhLQCBt4a8zzziFgEc1BKBhLhMmpKuIY8a2ebbWIrpKx2rXTBq+HJzPvC1qIu9SLpap4f4BNXUu67f+bIeoCG4SEZAjX9G6BFMFHldqQx1WL+rZH3+sSSU4wH7uc51ttoRGIP7lcsa2fPHKIShWCD4vVsTLY3goY93FdeDtjO/Op02q1GjFPpVeojdrXysx/AGOexQ9Ab9Thka6cWKzc3iye/n8OEK0yh3CicriKURbnQsFz9q6GrqRZyKAia2dHhxUqNNZxaZjHMGe2z+vJjzLkEQqh4ACdi+DpCrDgdq6SF/2thirI61OKjvDaV+xebGwst8DqWdzzb4bf78hitVIBG/oxxpVKXaLH3XiIDfKbqn7K8aGaJSW0djqUEl9o/9+vMzgkl4MD8pa7TXar3gi3eVCGZzg+h10F+lJ7JzqdxH9UbHi/GRVvL6UfGNkBW0p6Rl9HjJ4b3BORUjJdqnYBiZehYrqJIgWPeoLhc8GkHLFn1VaprRLi4o97W2gbKq5N7nu7Sj6otgKm/DzeH5D/68lNTgqeCjhjWlhqf9PDzHS5QlfZRReFCMpZ2GwDocKyXwgwQW8wCEbxDauIJ9f1vqffj5ZklVmk5qkyE5qVJDhjWz1C2NYacY3wwbrQ/hRyFOE3Hc2l0lBUCdnX9n5lUjcQkNIM1eN18ISu73teuPo X-Forefront-PRVS: 0261CCEEDF X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;SN1PR0301MB1550;23:dOh0V+3ZjESS+WTvmPNowdsorQe4sx6dT/jMkCA?= =?us-ascii?Q?FixBEzvOEebi8lJBS0EVGLJTVxqEUZ44nR7xCtHgtk4HTxqgaADk5bdJLKW3?= =?us-ascii?Q?1vnHlwW4lThO2kjk8cvGdqnKOQU4pVb1O7R0kxzBCUj+nGR2pvqcvDcYs0Te?= =?us-ascii?Q?C+tmN8OcLQR9m9Wk0xZlezxssyf9SE79vGBcE2UKPS/hhmcAeHtKoIwAasjW?= =?us-ascii?Q?YyPB5vsSS6lGLzsjYGnehaR8dS6NJJEbNlZQ6ehUEQCgqKICjI2kL0zCfVAj?= =?us-ascii?Q?VaVi5nLK7nyabxDASqNm+ZePyLHbVX6FYR5MD4tNk0jGDn0mlhdC+XYp8oZ8?= =?us-ascii?Q?zLKqNZgOPoQd3Bxn8aTujav+lVnk1AWNSgILsaAyoXzDp3RP7aVA9u+25OeU?= =?us-ascii?Q?dWJ6UKe6DN1E4ZuXEF3u0zTTlxhHo7dEcqhzqpGoyqKv9CADSCWbILu2FlyV?= =?us-ascii?Q?r6rbAIGEwgKqPlE4V5q/gr2wKFV4pht1riaR8Qm0S5ckKShTcrcEJaD6rhRc?= =?us-ascii?Q?CIp0Wa7utcAbhfDDqROeLtg6CkhExPoXdki7ekatpjoamHTAbm2s6vQ1nTTU?= =?us-ascii?Q?eO4bNzXSF5d3Y5KRXwfji50CZnqb/tg/wkaxdd0XuY3VbHpRqkR/JR9pwX4j?= =?us-ascii?Q?yP/yAyvLPV1Dw2rCGJ1aopNRmlWTLlgoux9tYIg2WA8V1+hC5Uju3hZWYBhD?= =?us-ascii?Q?YBKIG3CWsv7xsCs8ttnE0VltV5ykry7XRou/6vkXgO20TFChW5S2iv7a8ep/?= =?us-ascii?Q?fc5/SiJgVO6cUqUsf0kJ04OqTNs2s5BFlop6XB9uZbt1BxxmqNQzAVeUebSl?= =?us-ascii?Q?tJ2nSdwWpUX38ICW3uDch4KOEn9Mhg5eIao/Mu6ehM04AQirYqZtstTJLEg8?= =?us-ascii?Q?M+FbkPt3ABj8rQT8nBTlEJrnmrgPjrhxXOk/qqOX1YLGnuS/ko4DqwHMY0jV?= =?us-ascii?Q?DTwEMGRJCusrLA6N/rQMq9B+Gs4RASBXBcC9r28G/nB59wiaoVIs5Pw/cZLZ?= =?us-ascii?Q?0QC7YwrnoosQCBL0oAYXQy6VI08+KND8R5lHxruBP+RB9AYBtpa+kR2sQlrV?= =?us-ascii?Q?7yjtGA9U=3D?= X-Microsoft-Exchange-Diagnostics: 1;SN1PR0301MB1550;6:u3yMJ7Y4Ee/pdYTEAf9Kh7iCpqggA4kgY5m6OFVMfTOr0SG2SVAB9dBJGLRniTHw2SbOq8mOuAhrniWzJ4I+QdB6wJ7d9qE438aajWqavbr8k6Yz/N+pdAzWkOUoOI31R9dO32wBiqtQV8pQMLRi3TjxePGl/wDZ8y8BWsiZUnWTEyJonPMts0N0xZiKK7/UFfoFDp6o6SbsFVEX865RZ6ar2InI3HvSs+RQzloToEm4A9nrWYcSjjMgONuvTJPDJrkBWMZMmpmN1k/+5hDz8SAewRyM9b5bINifdxryTAiZ5I/IVJmvl6NdGo94k5MQ+i5DCgbgBSBWqVNN//7iGU97X9BW+rnPlyrbBfYEMGhsHB4zy3uRLap9apU6egmKvyUNVuJCXUw9LxGDXkGVwfYFscxo4nhpSGYQ6r2b81U=;5:g8M+zOqAgW4G3NR6wVDiM0V+S8b2xMcQHS1+7o00pXwCr82mOhF83PUbNWwesdAmg38N4QQXWoQ+ZJgf/vpcFXgtejERNXtUdc4ZK6woWfMh1VixIlxeh8lfyWpVmKPJhu4nc1hCUaiYLUwbfgdmbQ==;24:Ws+A3GTdx0MmM8d6NgJZ9szjKAgYQS/czOJjX2rbFjKVsTTC4O1a2TXOtd1b1BK/DImU23vZLIxdeC+Zfm1kK961mK8M8GlJoqg0Y9XlGBY= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1;SN1PR0301MB1550;7:tfZuEEsVbGipe37SjDn2uFI+mXDslWIVL/tvyciwYkX5zgcNN0/CwAWs2NuR7v3bpd9IBv8CU703QmB7D2R/bMRrny2DnD4TaGGqcNbYW2kAbAQvVRU5/BjTOp7QxrCOi7cBvwkVb0b8koqmQFXLLJwXlPRlyyLDXKzP4VHfjzmC7bieCoJ1qBa0Ke3PGz8dqOQbbtlYf/WmZenxdQgFbgyqB5S9a0QnYXma205V9OINLUNfLPBQum8lcd703RtaLnVRE6j/0GhFfmPgAFiXVcXc8gL3MGOdyH5MhgeEe0MmwRWgRvm4AtZ/CM1pkDXedohEsGAocMeTFROJ7xLQYw== X-OriginatorOrg: analog.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 29 Mar 2017 09:41:42.0439 (UTC) X-MS-Exchange-CrossTenant-Id: eaa689b4-8f87-40e0-9c6f-7228de4d754a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=eaa689b4-8f87-40e0-9c6f-7228de4d754a;Ip=[137.71.25.57];Helo=[nwd2mta2.analog.com] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN1PR0301MB1550 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 10748 Lines: 387 From: Michael Hennerich This patch adds support for the Analog Devices / Linear Technology LTC2497 ADCs. The LTC2497 is a 16-channel (eight differential), 16-bit, high precision, delta-sigma ADC with an automatic, differential, input current cancellation front end and a 2-wire, I2C interface. Signed-off-by: Michael Hennerich --- Changes since v1: - remove confusing kconfig help text - use proper defines - add descriptive comment - fix removal order - add poper commit mssage Changes since v2: - Sort includes - Use BIT() defines - Avoid transfer buffers on the stack - use msleep_interruptible() - Fix documentation s/Should/Must/g --- .../devicetree/bindings/iio/adc/ltc2497.txt | 13 + MAINTAINERS | 1 + drivers/iio/adc/Kconfig | 10 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ltc2497.c | 279 +++++++++++++++++++++ 5 files changed, 304 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/ltc2497.txt create mode 100644 drivers/iio/adc/ltc2497.c diff --git a/Documentation/devicetree/bindings/iio/adc/ltc2497.txt b/Documentation/devicetree/bindings/iio/adc/ltc2497.txt new file mode 100644 index 0000000..a237ed9 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/ltc2497.txt @@ -0,0 +1,13 @@ +* Linear Technology / Analog Devices LTC2497 ADC + +Required properties: + - compatible: Must be "lltc,ltc2497" + - reg: Must contain the ADC I2C address + - vref-supply: The regulator supply for ADC reference voltage + +Example: + ltc2497: adc@76 { + compatible = "lltc,ltc2497"; + reg = <0x76>; + vref-supply = <<c2497_reg>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index a7d6f9a..173043c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -813,6 +813,7 @@ W: http://wiki.analog.com/ W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/iio/*/ad* +F: drivers/iio/adc/ltc2497* X: drivers/iio/*/adjd* F: drivers/staging/iio/*/ad* F: drivers/staging/iio/trigger/iio-trig-bfin-timer.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 2268a6f..acc115b 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -326,6 +326,16 @@ config LTC2485 To compile this driver as a module, choose M here: the module will be called ltc2485. +config LTC2497 + tristate "Linear Technology LTC2497 ADC driver" + depends on I2C + help + Say yes here to build support for Linear Technology LTC2497 + 16-Bit 8-/16-Channel Delta Sigma ADC. + + To compile this driver as a module, choose M here: the module will be + called ltc2497. + config MAX1027 tristate "Maxim max1027 ADC driver" depends on SPI diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 73dbe39..9d626b5 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o obj-$(CONFIG_LTC2485) += ltc2485.o +obj-$(CONFIG_LTC2497) += ltc2497.o obj-$(CONFIG_MAX1027) += max1027.o obj-$(CONFIG_MAX11100) += max11100.o obj-$(CONFIG_MAX1363) += max1363.o diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c new file mode 100644 index 0000000..2691b10 --- /dev/null +++ b/drivers/iio/adc/ltc2497.c @@ -0,0 +1,279 @@ +/* + * ltc2497.c - Driver for Analog Devices/Linear Technology LTC2497 ADC + * + * Copyright (C) 2017 Analog Devices Inc. + * + * Licensed under the GPL-2. + * + * Datasheet: http://cds.linear.com/docs/en/datasheet/2497fd.pdf + */ + +#include +#include +#include +#include +#include +#include +#include + +#define LTC2497_ENABLE 0xA0 +#define LTC2497_SGL BIT(4) +#define LTC2497_DIFF 0 +#define LTC2497_SIGN BIT(3) +#define LTC2497_CONFIG_DEFAULT LTC2497_ENABLE +#define LTC2497_CONVERSION_TIME_MS 150ULL + +struct ltc2497_st { + struct i2c_client *client; + struct regulator *ref; + ktime_t time_prev; + u8 addr_prev; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + __be32 buf ____cacheline_aligned; +}; + +static int ltc2497_wait_conv(struct ltc2497_st *st) +{ + s64 time_elapsed; + + time_elapsed = ktime_ms_delta(ktime_get(), st->time_prev); + + if (time_elapsed < LTC2497_CONVERSION_TIME_MS) { + /* delay if conversion time not passed + * since last read or write + */ + if (msleep_interruptible( + LTC2497_CONVERSION_TIME_MS - time_elapsed)) + return -ERESTARTSYS; + + return 0; + } + + if (time_elapsed - LTC2497_CONVERSION_TIME_MS <= 0) { + /* We're in automatic mode - + * so the last reading is stil not outdated + */ + return 0; + } + + return 1; +} + +static int ltc2497_read(struct ltc2497_st *st, u8 address, int *val) +{ + struct i2c_client *client = st->client; + int ret; + + ret = ltc2497_wait_conv(st); + if (ret < 0) + return ret; + + if (ret || st->addr_prev != address) { + ret = i2c_smbus_write_byte(st->client, + LTC2497_ENABLE | address); + if (ret < 0) + return ret; + st->addr_prev = address; + if (msleep_interruptible(LTC2497_CONVERSION_TIME_MS)) + return -ERESTARTSYS; + } + ret = i2c_master_recv(client, (char *)&st->buf, 3); + if (ret < 0) { + dev_err(&client->dev, "i2c_master_recv failed\n"); + return ret; + } + st->time_prev = ktime_get(); + + /* convert and shift the result, + * and finally convert from offset binary to signed integer + */ + *val = (be32_to_cpu(st->buf) >> 14) - (1 << 17); + + return ret; +} + +static int ltc2497_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ltc2497_st *st = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&indio_dev->mlock); + ret = ltc2497_read(st, chan->address, val); + mutex_unlock(&indio_dev->mlock); + if (ret < 0) + return ret; + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + ret = regulator_get_voltage(st->ref); + if (ret < 0) + return ret; + + *val = ret / 1000; + *val2 = 17; + + return IIO_VAL_FRACTIONAL_LOG2; + + default: + return -EINVAL; + } +} + +#define LTC2497_CHAN(_chan, _addr) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (_chan), \ + .address = (_addr | (_chan / 2) | ((_chan & 1) ? LTC2497_SIGN : 0)), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +#define LTC2497_CHAN_DIFF(_chan, _addr) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 1 : 0), \ + .channel2 = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 0 : 1),\ + .address = (_addr | _chan), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .differential = 1, \ +} + +static const struct iio_chan_spec ltc2497_channel[] = { + LTC2497_CHAN(0, LTC2497_SGL), + LTC2497_CHAN(1, LTC2497_SGL), + LTC2497_CHAN(2, LTC2497_SGL), + LTC2497_CHAN(3, LTC2497_SGL), + LTC2497_CHAN(4, LTC2497_SGL), + LTC2497_CHAN(5, LTC2497_SGL), + LTC2497_CHAN(6, LTC2497_SGL), + LTC2497_CHAN(7, LTC2497_SGL), + LTC2497_CHAN(8, LTC2497_SGL), + LTC2497_CHAN(9, LTC2497_SGL), + LTC2497_CHAN(10, LTC2497_SGL), + LTC2497_CHAN(11, LTC2497_SGL), + LTC2497_CHAN(12, LTC2497_SGL), + LTC2497_CHAN(13, LTC2497_SGL), + LTC2497_CHAN(14, LTC2497_SGL), + LTC2497_CHAN(15, LTC2497_SGL), + LTC2497_CHAN_DIFF(0, LTC2497_DIFF), + LTC2497_CHAN_DIFF(1, LTC2497_DIFF), + LTC2497_CHAN_DIFF(2, LTC2497_DIFF), + LTC2497_CHAN_DIFF(3, LTC2497_DIFF), + LTC2497_CHAN_DIFF(4, LTC2497_DIFF), + LTC2497_CHAN_DIFF(5, LTC2497_DIFF), + LTC2497_CHAN_DIFF(6, LTC2497_DIFF), + LTC2497_CHAN_DIFF(7, LTC2497_DIFF), + LTC2497_CHAN_DIFF(0, LTC2497_DIFF | LTC2497_SIGN), + LTC2497_CHAN_DIFF(1, LTC2497_DIFF | LTC2497_SIGN), + LTC2497_CHAN_DIFF(2, LTC2497_DIFF | LTC2497_SIGN), + LTC2497_CHAN_DIFF(3, LTC2497_DIFF | LTC2497_SIGN), + LTC2497_CHAN_DIFF(4, LTC2497_DIFF | LTC2497_SIGN), + LTC2497_CHAN_DIFF(5, LTC2497_DIFF | LTC2497_SIGN), + LTC2497_CHAN_DIFF(6, LTC2497_DIFF | LTC2497_SIGN), + LTC2497_CHAN_DIFF(7, LTC2497_DIFF | LTC2497_SIGN), +}; + +static const struct iio_info ltc2497_info = { + .read_raw = ltc2497_read_raw, + .driver_module = THIS_MODULE, +}; + +static int ltc2497_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct ltc2497_st *st; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | + I2C_FUNC_SMBUS_WRITE_BYTE)) + return -EOPNOTSUPP; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + st->client = client; + + indio_dev->dev.parent = &client->dev; + indio_dev->name = id->name; + indio_dev->info = <c2497_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = ltc2497_channel; + indio_dev->num_channels = ARRAY_SIZE(ltc2497_channel); + + st->ref = devm_regulator_get(&client->dev, "vref"); + if (IS_ERR(st->ref)) + return PTR_ERR(st->ref); + + ret = regulator_enable(st->ref); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte(st->client, LTC2497_CONFIG_DEFAULT); + if (ret < 0) + goto err_regulator_disable; + + st->addr_prev = LTC2497_CONFIG_DEFAULT; + st->time_prev = ktime_get(); + + ret = iio_device_register(indio_dev); + if (ret < 0) + goto err_regulator_disable; + + return 0; + +err_regulator_disable: + regulator_disable(st->ref); + + return ret; +} + +static int ltc2497_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct ltc2497_st *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + regulator_disable(st->ref); + + return 0; +} + +static const struct i2c_device_id ltc2497_id[] = { + { "ltc2497", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ltc2497_id); + +static const struct of_device_id ltc2497_of_match[] = { + { .compatible = "lltc,ltc2497", }, + {}, +}; +MODULE_DEVICE_TABLE(of, ltc2497_of_match); + +static struct i2c_driver ltc2497_driver = { + .driver = { + .name = "ltc2497", + .of_match_table = of_match_ptr(ltc2497_of_match), + }, + .probe = ltc2497_probe, + .remove = ltc2497_remove, + .id_table = ltc2497_id, +}; +module_i2c_driver(ltc2497_driver); + +MODULE_AUTHOR("Michael Hennerich "); +MODULE_DESCRIPTION("Linear Technology LTC2497 ADC driver"); +MODULE_LICENSE("GPL v2"); -- 2.7.4