From patchwork Wed Oct 3 09:06:38 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Coffey X-Patchwork-Id: 10624511 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2A4AB14BD for ; Wed, 3 Oct 2018 09:21:35 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1DC092000A for ; Wed, 3 Oct 2018 09:21:35 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0F95A285A8; Wed, 3 Oct 2018 09:21:35 +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=-7.7 required=2.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI 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 657DB2000A for ; Wed, 3 Oct 2018 09:21:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726941AbeJCQJF (ORCPT ); Wed, 3 Oct 2018 12:09:05 -0400 Received: from mail.babblebit.net ([37.139.8.208]:49870 "EHLO mail.babblebit.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726216AbeJCQJF (ORCPT ); Wed, 3 Oct 2018 12:09:05 -0400 X-Greylist: delayed 455 seconds by postgrey-1.27 at vger.kernel.org; Wed, 03 Oct 2018 12:09:03 EDT Received: from localhost.localdomain (80-44-161-19.dynamic.dsl.as9105.com [80.44.161.19]) by mail.babblebit.net (Postfix) with ESMTPSA id 40D9420E52; Wed, 3 Oct 2018 09:13:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=babblebit.net; s=mail; t=1538558037; bh=3f0M4L5o/Yad123ZxAqTevKCMDlX845jeHjMBrSx8XQ=; h=From:To:Cc:Subject:Date:From; b=stLeVv0hiDYpVnSZ1AvDoAnC0l2JjTkKxBNUQjGmoHw9ksLuDHalDS9rR8fUCP0iE e+Y7/5Q6BkqXcGmvJWDaCE7eMuFBCXeKAbDXic+LSeCS4KNJCLMa4s5NnLuTly/5Tq bjIFfXWze+LBa+3SsjMGjkxzmoqpqcKSQCC654cY6DDR2OxxY28U7DzipsoBhkRREh tH4tvjcxQEEMumoWL5kR/+rDGM8OCQzAuOJykUvzKMifpkjCMDzmRvK20s/DEEGMJn XxatDgMxG1ybou8L9uq9GZXFPBJEITttb/82eVUvg7iXNccbt9GIPn6y7lpn7EVItA OV4qhk0ue4LMw== From: Chris Coffey To: Jonathan Cameron , Hartmut Knaack , Lars-Peter Clausen , Peter Meerwald-Stadler Cc: Michael Welling , linux-iio@vger.kernel.org, Chris Coffey Subject: [PATCH] iio: dac: mcp4922: Add powerdown support Date: Wed, 3 Oct 2018 10:06:38 +0100 Message-Id: <20181003090638.25111-1-cmc@babblebit.net> X-Mailer: git-send-email 2.11.0 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 adds support for per-channel powerdown on the Microchip MCP 4902/4912/4922 family of DACs. Signed-off-by: Chris Coffey --- drivers/iio/dac/mcp4922.c | 126 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 110 insertions(+), 16 deletions(-) diff --git a/drivers/iio/dac/mcp4922.c b/drivers/iio/dac/mcp4922.c index b5190d1dae..15cd17aa9d 100644 --- a/drivers/iio/dac/mcp4922.c +++ b/drivers/iio/dac/mcp4922.c @@ -28,6 +28,9 @@ #define MCP4922_NUM_CHANNELS 2 +#define MCP4922_OUTA_POWER_DOWN 0x20 +#define MCP4922_OUTB_POWER_DOWN 0xa0 + enum mcp4922_supported_device_ids { ID_MCP4902, ID_MCP4912, @@ -37,26 +40,13 @@ enum mcp4922_supported_device_ids { struct mcp4922_state { struct spi_device *spi; unsigned int value[MCP4922_NUM_CHANNELS]; + bool powerdown[MCP4922_NUM_CHANNELS]; + unsigned int powerdown_mode; unsigned int vref_mv; struct regulator *vref_reg; u8 mosi[2] ____cacheline_aligned; }; -#define MCP4922_CHAN(chan, bits) { \ - .type = IIO_VOLTAGE, \ - .output = 1, \ - .indexed = 1, \ - .channel = chan, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .scan_type = { \ - .sign = 'u', \ - .realbits = (bits), \ - .storagebits = 16, \ - .shift = 12 - (bits), \ - }, \ -} - static int mcp4922_spi_write(struct mcp4922_state *state, u8 addr, u32 val) { state->mosi[1] = val & 0xff; @@ -106,8 +96,10 @@ static int mcp4922_write_raw(struct iio_dev *indio_dev, val <<= chan->scan_type.shift; ret = mcp4922_spi_write(state, chan->channel, val); - if (!ret) + if (!ret) { state->value[chan->channel] = val; + state->powerdown[chan->channel] = false; + } return ret; default: @@ -115,6 +107,108 @@ static int mcp4922_write_raw(struct iio_dev *indio_dev, } } +static const char * const mcp4922_powerdown_modes[] = { + "500kohm_to_gnd" +}; + +static int mcp4922_get_powerdown_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct mcp4922_state *state = iio_priv(indio_dev); + + return state->powerdown_mode; +} + +static int mcp4922_set_powerdown_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int mode) +{ + struct mcp4922_state *state = iio_priv(indio_dev); + + state->powerdown_mode = mode; + + return 0; +} + +static ssize_t mcp4922_read_powerdown(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + struct mcp4922_state *state = iio_priv(indio_dev); + + return sprintf(buf, "%d\n", state->powerdown[chan->channel]); +} + +static ssize_t mcp4922_write_powerdown(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct mcp4922_state *state = iio_priv(indio_dev); + bool powerdown; + int ret; + + ret = strtobool(buf, &powerdown); + if (ret) + return ret; + + if (powerdown) { + state->mosi[0] = (chan->channel == 0) ? + MCP4922_OUTA_POWER_DOWN : + MCP4922_OUTB_POWER_DOWN; + state->mosi[1] = 0x00; + + ret = spi_write(state->spi, state->mosi, 2); + } else { + /* Restore previous voltage level */ + ret = mcp4922_write_raw(indio_dev, chan, + state->value[chan->channel], 0, + IIO_CHAN_INFO_RAW); + } + if (!ret) + state->powerdown[chan->channel] = powerdown; + + return ret ? ret : len; +} + +static const struct iio_enum mcp4922_powerdown_mode_enum = { + .items = mcp4922_powerdown_modes, + .num_items = ARRAY_SIZE(mcp4922_powerdown_modes), + .get = mcp4922_get_powerdown_mode, + .set = mcp4922_set_powerdown_mode, +}; + +static const struct iio_chan_spec_ext_info mcp4922_ext_info[] = { + { + .name = "powerdown", + .read = mcp4922_read_powerdown, + .write = mcp4922_write_powerdown, + .shared = IIO_SEPARATE, + }, + IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, + &mcp4922_powerdown_mode_enum), + IIO_ENUM_AVAILABLE("powerdown_mode", + &mcp4922_powerdown_mode_enum), + { }, +}; + +#define MCP4922_CHAN(chan, bits) { \ + .type = IIO_VOLTAGE, \ + .output = 1, \ + .indexed = 1, \ + .channel = chan, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = 12 - (bits), \ + }, \ + .ext_info = mcp4922_ext_info, \ +} + static const struct iio_chan_spec mcp4922_channels[3][MCP4922_NUM_CHANNELS] = { [ID_MCP4902] = { MCP4922_CHAN(0, 8), MCP4922_CHAN(1, 8) }, [ID_MCP4912] = { MCP4922_CHAN(0, 10), MCP4922_CHAN(1, 10) },