From patchwork Wed Sep 20 15:18:10 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Icenowy Zheng X-Patchwork-Id: 9961681 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 1E82560208 for ; Wed, 20 Sep 2017 15:21:00 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 10FD328867 for ; Wed, 20 Sep 2017 15:21:00 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 05B3D288EF; Wed, 20 Sep 2017 15:21:00 +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.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable 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 974A828867 for ; Wed, 20 Sep 2017 15:20:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751593AbdITPTD (ORCPT ); Wed, 20 Sep 2017 11:19:03 -0400 Received: from hermes.aosc.io ([199.195.250.187]:41667 "EHLO hermes.aosc.io" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751507AbdITPTB (ORCPT ); Wed, 20 Sep 2017 11:19:01 -0400 Received: from localhost (localhost [127.0.0.1]) (Authenticated sender: icenowy@aosc.io) by hermes.aosc.io (Postfix) with ESMTPSA id 3094B47941; Wed, 20 Sep 2017 15:18:55 +0000 (UTC) From: Icenowy Zheng To: Chen-Yu Tsai , Maxime Ripard , Jonathan Cameron , Lee Jones , Quentin Schulz Cc: linux-pm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-iio@vger.kernel.org, linux-sunxi@googlegroups.com, Icenowy Zheng Subject: [RFC PATCH 3/7] iio: adc: axp20x-adc: add support for AXP803 Date: Wed, 20 Sep 2017 23:18:10 +0800 Message-Id: <20170920151814.22461-4-icenowy@aosc.io> In-Reply-To: <20170920151814.22461-1-icenowy@aosc.io> References: <20170920151814.22461-1-icenowy@aosc.io> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP AXP803 SoC features an ADC part including these channels: GPADC (GPIO0) and TS pins, PMIC internal temperature sensor, battery voltage, battery charge/discharge current. Add support for the battery-related channels and internal temperature channel in order to allow battery monitoring. The TS and GPADC channels are complex and will be support after more investigation. Signed-off-by: Icenowy Zheng --- drivers/iio/adc/axp20x_adc.c | 108 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c index 93dd6b80059e..4f0cd98cf6ea 100644 --- a/drivers/iio/adc/axp20x_adc.c +++ b/drivers/iio/adc/axp20x_adc.c @@ -28,6 +28,8 @@ #define AXP20X_ADC_EN2_MASK (GENMASK(3, 2) | BIT(7)) #define AXP22X_ADC_EN1_MASK (GENMASK(7, 5) | BIT(0)) +/* TODO: Enable TS and GPADC when supporting them */ +#define AXP803_ADC_EN1_MASK GENMASK(7, 5) #define AXP20X_GPIO10_IN_RANGE_GPIO0 BIT(0) #define AXP20X_GPIO10_IN_RANGE_GPIO1 BIT(1) @@ -95,6 +97,17 @@ enum axp22x_adc_channel_i { AXP22X_BATT_DISCHRG_I, }; +enum axp803_adc_channel_v { + AXP803_TS_IN = 0, + AXP803_GPADC_IN, + AXP803_BATT_V, +}; + +enum axp803_adc_channel_i { + AXP803_BATT_CHRG_I = 2, + AXP803_BATT_DISCHRG_I, +}; + static struct iio_map axp20x_maps[] = { { .consumer_dev_name = "axp20x-usb-power-supply", @@ -144,6 +157,11 @@ static struct iio_map axp22x_maps[] = { }; /* + * AXP803 shares the same consumer map with AXP22x, as it has no ADC for + * VBUS and ACIN inputs either. + */ + +/* * Channels are mapped by physical system. Their channels share the same index. * i.e. acin_i is in_current0_raw and acin_v is in_voltage0_raw. * The only exception is for the battery. batt_v will be in_voltage6_raw and @@ -197,6 +215,23 @@ static const struct iio_chan_spec axp22x_adc_channels[] = { AXP20X_BATT_DISCHRG_I_H), }; +static const struct iio_chan_spec axp803_adc_channels[] = { + { + .type = IIO_TEMP, + .address = AXP288_PMIC_ADC_H, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + .datasheet_name = "pmic_temp", + }, + AXP20X_ADC_CHANNEL(AXP803_BATT_V, "batt_v", IIO_VOLTAGE, + AXP20X_BATT_V_H), + AXP20X_ADC_CHANNEL(AXP803_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT, + AXP20X_BATT_CHRG_I_H), + AXP20X_ADC_CHANNEL(AXP803_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT, + AXP20X_BATT_DISCHRG_I_H), +}; + static int axp20x_adc_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val) { @@ -243,6 +278,19 @@ static int axp22x_adc_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; } +static int axp803_adc_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val) +{ + struct axp20x_adc_iio *info = iio_priv(indio_dev); + + /* All channels on AXP803 are stored on 12 bits. */ + *val = axp20x_read_variable_width(info->regmap, chan->address, 12); + if (*val < 0) + return *val; + + return IIO_VAL_INT; +} + static int axp20x_adc_scale_voltage(int channel, int *val, int *val2) { switch (channel) { @@ -342,6 +390,31 @@ static int axp22x_adc_scale(struct iio_chan_spec const *chan, int *val, } } +static int axp803_adc_scale(struct iio_chan_spec const *chan, int *val, + int *val2) +{ + switch (chan->type) { + case IIO_VOLTAGE: + if (chan->channel != AXP803_BATT_V) + return -EINVAL; + + *val = 1; + *val2 = 100000; + return IIO_VAL_INT_PLUS_MICRO; + + case IIO_CURRENT: + *val = 1; + return IIO_VAL_INT; + + case IIO_TEMP: + *val = 106; + return IIO_VAL_INT; + + default: + return -EINVAL; + } +} + static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel, int *val) { @@ -425,6 +498,26 @@ static int axp22x_read_raw(struct iio_dev *indio_dev, } } +static int axp803_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_OFFSET: + *val = -2525; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + return axp803_adc_scale(chan, val, val2); + + case IIO_CHAN_INFO_RAW: + return axp803_adc_raw(indio_dev, chan, val); + + default: + return -EINVAL; + } +} + static int axp20x_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) @@ -472,6 +565,11 @@ static const struct iio_info axp22x_adc_iio_info = { .driver_module = THIS_MODULE, }; +static const struct iio_info axp803_adc_iio_info = { + .read_raw = axp803_read_raw, + .driver_module = THIS_MODULE, +}; + static int axp20x_adc_rate(int rate) { return AXP20X_ADC_RATE_HZ(rate); @@ -512,9 +610,19 @@ static const struct axp_data axp22x_data = { .maps = axp22x_maps, }; +static const struct axp_data axp803_data = { + .iio_info = &axp803_adc_iio_info, + .num_channels = ARRAY_SIZE(axp803_adc_channels), + .channels = axp803_adc_channels, + .adc_en1_mask = AXP803_ADC_EN1_MASK, + .adc_en2 = false, + .maps = axp22x_maps, +}; + static const struct platform_device_id axp20x_adc_id_match[] = { { .name = "axp20x-adc", .driver_data = (kernel_ulong_t)&axp20x_data, }, { .name = "axp22x-adc", .driver_data = (kernel_ulong_t)&axp22x_data, }, + { .name = "axp803-adc", .driver_data = (kernel_ulong_t)&axp803_data, }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(platform, axp20x_adc_id_match);