From patchwork Sun Mar 19 22:39:06 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Patrik_Dahlstr=C3=B6m?= X-Patchwork-Id: 13180650 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 170BEC7618A for ; Sun, 19 Mar 2023 22:39:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230027AbjCSWjp convert rfc822-to-8bit (ORCPT ); Sun, 19 Mar 2023 18:39:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33262 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229975AbjCSWjm (ORCPT ); Sun, 19 Mar 2023 18:39:42 -0400 Received: from ste-pvt-msa1.bahnhof.se (ste-pvt-msa1.bahnhof.se [213.80.101.70]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 06E181B553; Sun, 19 Mar 2023 15:39:38 -0700 (PDT) Received: from localhost (localhost [127.0.0.1]) by ste-pvt-msa1.bahnhof.se (Postfix) with ESMTP id 0F3A63F6C8; Sun, 19 Mar 2023 23:39:37 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at bahnhof.se Received: from ste-pvt-msa1.bahnhof.se ([127.0.0.1]) by localhost (ste-pvt-msa1.bahnhof.se [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 2of0CKLjTdBz; Sun, 19 Mar 2023 23:39:35 +0100 (CET) Received: by ste-pvt-msa1.bahnhof.se (Postfix) with ESMTPA id 9AA8A3F312; Sun, 19 Mar 2023 23:39:35 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by zimbra.dalakolonin.se (Postfix) with ESMTP id EFE9A8EBD9; Sun, 19 Mar 2023 22:39:28 +0000 (UTC) Received: from zimbra.dalakolonin.se ([127.0.0.1]) by localhost (zimbra.dalakolonin.se [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id PkoJ02eyUkIm; Sun, 19 Mar 2023 22:39:21 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by zimbra.dalakolonin.se (Postfix) with ESMTP id 532BB8EBC7; Sun, 19 Mar 2023 22:39:21 +0000 (UTC) X-Virus-Scanned: amavisd-new at dalakolonin.se Received: from zimbra.dalakolonin.se ([127.0.0.1]) by localhost (zimbra.dalakolonin.se [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id 7hh3nitNxso3; Sun, 19 Mar 2023 22:39:20 +0000 (UTC) Received: from rack-server-1.dalakolonin.se (unknown [172.17.0.1]) by zimbra.dalakolonin.se (Postfix) with ESMTPSA id 5F6EA8EBB5; Sun, 19 Mar 2023 22:39:20 +0000 (UTC) From: =?utf-8?q?Patrik_Dahlstr=C3=B6m?= To: linux-iio@vger.kernel.org Cc: linux-kernel@vger.kernel.org, letux-kernel@openphoenux.org, kernel@pyra-handheld.com, pgoudagunta@nvidia.com, hns@goldelico.com, jic23@kernel.org, lars@metafoo.de, =?utf-8?q?Patrik_Dahlstr=C3=B6m?= Subject: [PATCH 1/3] iio: adc: palmas_gpadc: add support for iio threshold events Date: Sun, 19 Mar 2023 23:39:06 +0100 Message-Id: <20230319223908.108540-2-risca@dalakolonin.se> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230319223908.108540-1-risca@dalakolonin.se> References: <20230319223908.108540-1-risca@dalakolonin.se> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org The palmas gpadc block has support for monitoring up to 2 ADC channels and issue an interrupt if they reach past a set threshold. The gpadc driver had limited support for this through the adc_wakeup{1,2}_data platform data. This however only allow a fixed threshold to be set at boot, and would only enable it when entering sleep mode. This change hooks into the IIO events system and exposes to userspace the ability to configure threshold values for each channel individually, but only allow up to 2 such thresholds to be enabled at any given time. The logic around suspend and resume had to be adjusted so that user space configuration don't get reset on resume. Instead, any configured adc auto wakeup gets enabled during probe. Enabling a threshold from userspace will overwrite the adc wakeup configuration set during probe. Depending on how you look at it, this could also mean we allow userspace to update the adc wakeup thresholds. Signed-off-by: Patrik Dahlström --- drivers/iio/adc/palmas_gpadc.c | 495 +++++++++++++++++++++++++++++---- 1 file changed, 438 insertions(+), 57 deletions(-) diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c index 24d7c096e4b8..84c6e3b66205 100644 --- a/drivers/iio/adc/palmas_gpadc.c +++ b/drivers/iio/adc/palmas_gpadc.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -76,6 +77,16 @@ static struct palmas_gpadc_info palmas_gpadc_info[] = { PALMAS_ADC_INFO(IN15, 0, 0, 0, 0, INVALID, INVALID, true), }; +struct palmas_gpadc_thresholds { + int high_thresh; + int low_thresh; +}; + +struct palmas_adc_event { + int channel; + enum iio_event_direction direction; +}; + /* * struct palmas_gpadc - the palmas_gpadc structure * @ch0_current: channel 0 current source setting @@ -117,8 +128,30 @@ struct palmas_gpadc { bool wakeup2_enable; int auto_conversion_period; struct mutex lock; + struct palmas_adc_event event0; + struct palmas_adc_event event1; + struct palmas_gpadc_thresholds thresh_data[PALMAS_ADC_CH_MAX]; }; +static struct palmas_adc_event *palmas_gpadc_get_event_channel( + struct palmas_gpadc *adc, int adc_chan, enum iio_event_direction dir) +{ + if (adc_chan == adc->event0.channel && dir == adc->event0.direction) + return &adc->event0; + + if (adc_chan == adc->event1.channel && dir == adc->event1.direction) + return &adc->event1; + + return NULL; +} + +static bool palmas_gpadc_channel_is_freerunning(struct palmas_gpadc *adc, + int adc_chan) +{ + return palmas_gpadc_get_event_channel(adc, adc_chan, IIO_EV_DIR_RISING) || + palmas_gpadc_get_event_channel(adc, adc_chan, IIO_EV_DIR_FALLING); +} + /* * GPADC lock issue in AUTO mode. * Impact: In AUTO mode, GPADC conversion can be locked after disabling AUTO @@ -188,11 +221,24 @@ static irqreturn_t palmas_gpadc_irq(int irq, void *data) static irqreturn_t palmas_gpadc_irq_auto(int irq, void *data) { - struct palmas_gpadc *adc = data; + struct iio_dev *indio_dev = data; + struct palmas_gpadc *adc = iio_priv(indio_dev); + struct palmas_adc_event *ev; dev_dbg(adc->dev, "Threshold interrupt %d occurs\n", irq); palmas_disable_auto_conversion(adc); + ev = (irq == adc->irq_auto_0) ? &adc->event0 : &adc->event1; + if (ev->channel != -1) { + enum iio_event_direction dir; + u64 code; + + dir = ev->direction; + code = IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, ev->channel, + IIO_EV_TYPE_THRESH, dir); + iio_push_event(indio_dev, code, iio_get_time_ns(indio_dev)); + } + return IRQ_HANDLED; } @@ -280,6 +326,9 @@ static int palmas_gpadc_read_prepare(struct palmas_gpadc *adc, int adc_chan) { int ret; + if (palmas_gpadc_channel_is_freerunning(adc, adc_chan)) + return 0; // ADC already running + ret = palmas_gpadc_enable(adc, adc_chan, true); if (ret < 0) return ret; @@ -339,28 +388,44 @@ static int palmas_gpadc_start_conversion(struct palmas_gpadc *adc, int adc_chan) unsigned int val; int ret; - init_completion(&adc->conv_completion); - ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE, - PALMAS_GPADC_SW_SELECT, - PALMAS_GPADC_SW_SELECT_SW_START_CONV0, - PALMAS_GPADC_SW_SELECT_SW_START_CONV0); - if (ret < 0) { - dev_err(adc->dev, "SELECT_SW_START write failed: %d\n", ret); - return ret; - } + if (palmas_gpadc_channel_is_freerunning(adc, adc_chan)) { + int event = (adc_chan == adc->event0.channel) ? 0 : 1; + unsigned int reg = (event == 0) ? + PALMAS_GPADC_AUTO_CONV0_LSB : + PALMAS_GPADC_AUTO_CONV1_LSB; - ret = wait_for_completion_timeout(&adc->conv_completion, - PALMAS_ADC_CONVERSION_TIMEOUT); - if (ret == 0) { - dev_err(adc->dev, "conversion not completed\n"); - return -ETIMEDOUT; + ret = palmas_bulk_read(adc->palmas, PALMAS_GPADC_BASE, + reg, &val, 2); + if (ret < 0) { + dev_err(adc->dev, "AUTO_CONV%x_LSB read failed: %d\n", + event, ret); + return ret; + } } + else { + init_completion(&adc->conv_completion); + ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE, + PALMAS_GPADC_SW_SELECT, + PALMAS_GPADC_SW_SELECT_SW_START_CONV0, + PALMAS_GPADC_SW_SELECT_SW_START_CONV0); + if (ret < 0) { + dev_err(adc->dev, "SELECT_SW_START write failed: %d\n", ret); + return ret; + } - ret = palmas_bulk_read(adc->palmas, PALMAS_GPADC_BASE, - PALMAS_GPADC_SW_CONV0_LSB, &val, 2); - if (ret < 0) { - dev_err(adc->dev, "SW_CONV0_LSB read failed: %d\n", ret); - return ret; + ret = wait_for_completion_timeout(&adc->conv_completion, + PALMAS_ADC_CONVERSION_TIMEOUT); + if (ret == 0) { + dev_err(adc->dev, "conversion not completed\n"); + return -ETIMEDOUT; + } + + ret = palmas_bulk_read(adc->palmas, PALMAS_GPADC_BASE, + PALMAS_GPADC_SW_CONV0_LSB, &val, 2); + if (ret < 0) { + dev_err(adc->dev, "SW_CONV0_LSB read failed: %d\n", ret); + return ret; + } } ret = val & 0xFFF; @@ -385,6 +450,80 @@ static int palmas_gpadc_get_calibrated_code(struct palmas_gpadc *adc, return val; } +static int palmas_gpadc_get_high_threshold_raw(struct palmas_gpadc *adc, + struct palmas_adc_event *ev) +{ + const int INL = 2; + const int adc_chan = ev->channel; + const int orig = adc->thresh_data[adc_chan].high_thresh; + int val = orig; + int gain_drift; + int offset_drift; + + if (!val) + return 0; + + val = (val * 1000) / adc->adc_info[adc_chan].gain; + + if (!adc->adc_info[adc_chan].is_uncalibrated) { + val = (val * adc->adc_info[adc_chan].gain_error + + adc->adc_info[adc_chan].offset) / + 1000; + gain_drift = 1002; + offset_drift = 2; + } + else { + gain_drift = 1022; + offset_drift = 36; + } + + // add tolerance to threshold + val = ((val + INL) * gain_drift) / 1000 + offset_drift; + + // clamp to max possible value + if (val > 0xFFF) + val = 0xFFF; + + return val; +} + +static int palmas_gpadc_get_low_threshold_raw(struct palmas_gpadc *adc, + struct palmas_adc_event *ev) +{ + const int INL = 2; + const int adc_chan = ev->channel; + const int orig = adc->thresh_data[adc_chan].low_thresh; + int val = orig; + int gain_drift; + int offset_drift; + + if (!val) + return val; + + val = (val * 1000) / adc->adc_info[adc_chan].gain; + + if (!adc->adc_info[adc_chan].is_uncalibrated) { + val = (val * adc->adc_info[adc_chan].gain_error - + adc->adc_info[adc_chan].offset) / + 1000; + gain_drift = 998; + offset_drift = 2; + } + else { + gain_drift = 978; + offset_drift = 36; + } + + // calculate tolerances + val = ((val - INL) * gain_drift) / 1000 - offset_drift; + + // clamp to minimum 0 + if (val < 0) + val = 0; + + return val; +} + static int palmas_gpadc_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { @@ -431,8 +570,239 @@ static int palmas_gpadc_read_raw(struct iio_dev *indio_dev, return ret; } +static int palmas_gpadc_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir) +{ + struct palmas_gpadc *adc = iio_priv(indio_dev); + int adc_chan = chan->channel; + int ret = 0; + + if (adc_chan > PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH) + return -EINVAL; + + mutex_lock(&adc->lock); + + if (palmas_gpadc_get_event_channel(adc, adc_chan, dir)) { + ret = 1; + } + + mutex_unlock(&adc->lock); + + return ret; +} + +static void palmas_adc_event_to_wakeup(struct palmas_gpadc *adc, + struct palmas_adc_event *ev, + struct palmas_adc_wakeup_property *wakeup) +{ + wakeup->adc_channel_number = ev->channel; + if (ev->direction == IIO_EV_DIR_RISING) { + wakeup->adc_low_threshold = 0; + wakeup->adc_high_threshold = + palmas_gpadc_get_high_threshold_raw(adc, &adc->event0); + } + else { + wakeup->adc_low_threshold = + palmas_gpadc_get_low_threshold_raw(adc, &adc->event0); + wakeup->adc_high_threshold = 0; + } +} + +static int palmas_adc_wakeup_configure(struct palmas_gpadc *adc); +static int palmas_adc_wakeup_reset(struct palmas_gpadc *adc); + +static int palmas_gpadc_reconfigure_event_channels(struct palmas_gpadc *adc) +{ + bool was_enabled = adc->wakeup1_enable || adc->wakeup2_enable; + bool enable; + + adc->wakeup1_enable = adc->event0.channel == -1 ? false : true; + adc->wakeup2_enable = adc->event1.channel == -1 ? false : true; + + enable = adc->wakeup1_enable || adc->wakeup2_enable; + if (!was_enabled && enable) + device_wakeup_enable(adc->dev); + else if (was_enabled && !enable) + device_wakeup_disable(adc->dev); + + if (!enable) + return palmas_adc_wakeup_reset(adc); + + // adjust levels + if (adc->wakeup1_enable) + palmas_adc_event_to_wakeup(adc, &adc->event0, &adc->wakeup1_data); + if (adc->wakeup2_enable) + palmas_adc_event_to_wakeup(adc, &adc->event1, &adc->wakeup2_data); + + return palmas_adc_wakeup_configure(adc); +} + +static int palmas_gpadc_enable_event_config(struct palmas_gpadc *adc, + const struct iio_chan_spec *chan, enum iio_event_direction dir) +{ + struct palmas_adc_event *ev; + int adc_chan = chan->channel; + + if (palmas_gpadc_get_event_channel(adc, adc_chan, dir)) + /* already enabled */ + return 0; + + if (adc->event0.channel == -1) + ev = &adc->event0; + else if (adc->event1.channel == -1) { + /* event0 has to be the lowest channel */ + if (adc_chan < adc->event0.channel) { + adc->event1 = adc->event0; + ev = &adc->event0; + } + else + ev = &adc->event1; + } + else /* both AUTO channels already in use */ { + dev_warn(adc->dev, "event0 - %d, event1 - %d\n", + adc->event0.channel, adc->event1.channel); + return -EBUSY; + } + + ev->channel = adc_chan; + ev->direction = dir; + + return palmas_gpadc_reconfigure_event_channels(adc); +} + +static int palmas_gpadc_disable_event_config(struct palmas_gpadc *adc, + const struct iio_chan_spec *chan, enum iio_event_direction dir) +{ + int adc_chan = chan->channel; + struct palmas_adc_event *ev = + palmas_gpadc_get_event_channel(adc, adc_chan, dir); + + if (!ev) + return 0; + + if (ev == &adc->event0) { + adc->event0 = adc->event1; + ev = &adc->event1; + } + + ev->channel = -1; + ev->direction = IIO_EV_DIR_NONE; + + return palmas_gpadc_reconfigure_event_channels(adc); +} + +static int palmas_gpadc_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, int state) +{ + struct palmas_gpadc *adc = iio_priv(indio_dev); + int adc_chan = chan->channel; + int ret = 0; + + if (adc_chan > PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH) + return -EINVAL; + + mutex_lock(&adc->lock); + + if (state) + ret = palmas_gpadc_enable_event_config(adc, chan, dir); + else + ret = palmas_gpadc_disable_event_config(adc, chan, dir); + + mutex_unlock(&adc->lock); + + return ret; +} + +static int palmas_gpadc_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, int *val, + int *val2) +{ + struct palmas_gpadc *adc = iio_priv(indio_dev); + int adc_chan = chan->channel; + int ret = 0; + + if (adc_chan > PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH) + return -EINVAL; + + mutex_lock(&adc->lock); + + switch (info) { + case IIO_EV_INFO_VALUE: + *val = (dir == IIO_EV_DIR_RISING) ? + adc->thresh_data[adc_chan].high_thresh : + adc->thresh_data[adc_chan].low_thresh; + ret = IIO_VAL_INT; + break; + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&adc->lock); + + return ret; +} + +static int palmas_gpadc_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, int val, + int val2) +{ + struct palmas_gpadc *adc = iio_priv(indio_dev); + int adc_chan = chan->channel; + int ret = 0; + + if (adc_chan > PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH) + return -EINVAL; + + mutex_lock(&adc->lock); + switch (info) { + case IIO_EV_INFO_VALUE: + if (val < 0 || val > 0xFFF) { + ret = -EINVAL; + break; + } + if (dir == IIO_EV_DIR_RISING) + adc->thresh_data[adc_chan].high_thresh = val; + else + adc->thresh_data[adc_chan].low_thresh = val; + break; + default: + ret = -EINVAL; + break; + } + + if (palmas_gpadc_get_event_channel(adc, adc_chan, dir)) + ret = palmas_gpadc_reconfigure_event_channels(adc); + + mutex_unlock(&adc->lock); + + return ret; +} + static const struct iio_info palmas_gpadc_iio_info = { .read_raw = palmas_gpadc_read_raw, + .read_event_config = palmas_gpadc_read_event_config, + .write_event_config = palmas_gpadc_write_event_config, + .read_event_value = palmas_gpadc_read_event_value, + .write_event_value = palmas_gpadc_write_event_value, +}; + +static const struct iio_event_spec palmas_gpadc_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, }; #define PALMAS_ADC_CHAN_IIO(chan, _type, chan_info) \ @@ -443,6 +813,8 @@ static const struct iio_info palmas_gpadc_iio_info = { BIT(chan_info), \ .indexed = 1, \ .channel = PALMAS_ADC_CH_##chan, \ + .event_spec = palmas_gpadc_events, \ + .num_event_specs = ARRAY_SIZE(palmas_gpadc_events) \ } static const struct iio_chan_spec palmas_gpadc_iio_channel[] = { @@ -492,9 +864,12 @@ static int palmas_gpadc_get_adc_dt_data(struct platform_device *pdev, return 0; } -static void palmas_disable_wakeup(void *dev) +static void palmas_disable_wakeup(void *data) { - device_wakeup_disable(dev); + struct palmas_gpadc *adc = data; + + if (adc->wakeup1_enable || adc->wakeup2_enable) + device_wakeup_disable(adc->dev); } static int palmas_gpadc_probe(struct platform_device *pdev) @@ -547,36 +922,49 @@ static int palmas_gpadc_probe(struct platform_device *pdev) return dev_err_probe(adc->dev, ret, "request irq %d failed\n", adc->irq); + adc->irq_auto_0 = platform_get_irq(pdev, 1); + if (adc->irq_auto_0 < 0) + return dev_err_probe(adc->dev, adc->irq_auto_0, + "get auto0 irq failed\n"); + + ret = devm_request_threaded_irq(&pdev->dev, adc->irq_auto_0, NULL, + palmas_gpadc_irq_auto, IRQF_ONESHOT, + "palmas-adc-auto-0", indio_dev); + if (ret < 0) + return dev_err_probe(adc->dev, ret, + "request auto0 irq %d failed\n", + adc->irq_auto_0); + + adc->irq_auto_1 = platform_get_irq(pdev, 2); + if (adc->irq_auto_1 < 0) + return dev_err_probe(adc->dev, adc->irq_auto_1, + "get auto1 irq failed\n"); + + ret = devm_request_threaded_irq(&pdev->dev, adc->irq_auto_1, NULL, + palmas_gpadc_irq_auto, IRQF_ONESHOT, + "palmas-adc-auto-1", indio_dev); + if (ret < 0) + return dev_err_probe(adc->dev, ret, + "request auto1 irq %d failed\n", + adc->irq_auto_1); + if (gpadc_pdata->adc_wakeup1_data) { memcpy(&adc->wakeup1_data, gpadc_pdata->adc_wakeup1_data, sizeof(adc->wakeup1_data)); adc->wakeup1_enable = true; - adc->irq_auto_0 = platform_get_irq(pdev, 1); - ret = devm_request_threaded_irq(&pdev->dev, adc->irq_auto_0, - NULL, palmas_gpadc_irq_auto, - IRQF_ONESHOT, - "palmas-adc-auto-0", adc); - if (ret < 0) - return dev_err_probe(adc->dev, ret, - "request auto0 irq %d failed\n", - adc->irq_auto_0); } if (gpadc_pdata->adc_wakeup2_data) { memcpy(&adc->wakeup2_data, gpadc_pdata->adc_wakeup2_data, sizeof(adc->wakeup2_data)); adc->wakeup2_enable = true; - adc->irq_auto_1 = platform_get_irq(pdev, 2); - ret = devm_request_threaded_irq(&pdev->dev, adc->irq_auto_1, - NULL, palmas_gpadc_irq_auto, - IRQF_ONESHOT, - "palmas-adc-auto-1", adc); - if (ret < 0) - return dev_err_probe(adc->dev, ret, - "request auto1 irq %d failed\n", - adc->irq_auto_1); } + adc->event0.channel = -1; + adc->event0.direction = IIO_EV_DIR_NONE; + adc->event1.channel = -1; + adc->event1.direction = IIO_EV_DIR_NONE; + /* set the current source 0 (value 0/5/15/20 uA => 0..3) */ if (gpadc_pdata->ch0_current <= 1) adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_0; @@ -610,20 +998,23 @@ static int palmas_gpadc_probe(struct platform_device *pdev) return dev_err_probe(adc->dev, ret, "iio_device_register() failed\n"); - device_set_wakeup_capable(&pdev->dev, 1); for (i = 0; i < PALMAS_ADC_CH_MAX; i++) { if (!(adc->adc_info[i].is_uncalibrated)) palmas_gpadc_calibrate(adc, i); } + device_set_wakeup_capable(&pdev->dev, 1); if (adc->wakeup1_enable || adc->wakeup2_enable) { - device_wakeup_enable(&pdev->dev); - ret = devm_add_action_or_reset(&pdev->dev, - palmas_disable_wakeup, - &pdev->dev); + ret = palmas_adc_wakeup_configure(adc); if (ret) return ret; + device_wakeup_enable(&pdev->dev); } + ret = devm_add_action_or_reset(&pdev->dev, + palmas_disable_wakeup, + adc); + if (ret) + return ret; return 0; } @@ -755,16 +1146,11 @@ static int palmas_gpadc_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct palmas_gpadc *adc = iio_priv(indio_dev); - int wakeup = adc->wakeup1_enable || adc->wakeup2_enable; int ret; - if (!device_may_wakeup(dev) || !wakeup) + if (!device_may_wakeup(dev)) return 0; - ret = palmas_adc_wakeup_configure(adc); - if (ret < 0) - return ret; - if (adc->wakeup1_enable) enable_irq_wake(adc->irq_auto_0); @@ -778,16 +1164,11 @@ static int palmas_gpadc_resume(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct palmas_gpadc *adc = iio_priv(indio_dev); - int wakeup = adc->wakeup1_enable || adc->wakeup2_enable; int ret; - if (!device_may_wakeup(dev) || !wakeup) + if (!device_may_wakeup(dev)) return 0; - ret = palmas_adc_wakeup_reset(adc); - if (ret < 0) - return ret; - if (adc->wakeup1_enable) disable_irq_wake(adc->irq_auto_0); From patchwork Sun Mar 19 22:39:07 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Patrik_Dahlstr=C3=B6m?= X-Patchwork-Id: 13180647 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2D6F3C6FD1F for ; Sun, 19 Mar 2023 22:39:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229937AbjCSWjm convert rfc822-to-8bit (ORCPT ); Sun, 19 Mar 2023 18:39:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33252 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229657AbjCSWjk (ORCPT ); Sun, 19 Mar 2023 18:39:40 -0400 Received: from pio-pvt-msa1.bahnhof.se (pio-pvt-msa1.bahnhof.se [79.136.2.40]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D4A5B1B552; Sun, 19 Mar 2023 15:39:38 -0700 (PDT) Received: from localhost (localhost [127.0.0.1]) by pio-pvt-msa1.bahnhof.se (Postfix) with ESMTP id 480133FAD8; Sun, 19 Mar 2023 23:39:37 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at bahnhof.se Received: from pio-pvt-msa1.bahnhof.se ([127.0.0.1]) by localhost (pio-pvt-msa1.bahnhof.se [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id KJhJgw-w8jRe; Sun, 19 Mar 2023 23:39:36 +0100 (CET) Received: by pio-pvt-msa1.bahnhof.se (Postfix) with ESMTPA id 76B533F55C; Sun, 19 Mar 2023 23:39:36 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by zimbra.dalakolonin.se (Postfix) with ESMTP id E33478EBDC; Sun, 19 Mar 2023 22:39:29 +0000 (UTC) Received: from zimbra.dalakolonin.se ([127.0.0.1]) by localhost (zimbra.dalakolonin.se [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id 2jlj8NBE25Am; Sun, 19 Mar 2023 22:39:21 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by zimbra.dalakolonin.se (Postfix) with ESMTP id 4C6448EBC6; Sun, 19 Mar 2023 22:39:21 +0000 (UTC) X-Virus-Scanned: amavisd-new at dalakolonin.se Received: from zimbra.dalakolonin.se ([127.0.0.1]) by localhost (zimbra.dalakolonin.se [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id sJCR34fAC0WB; Sun, 19 Mar 2023 22:39:20 +0000 (UTC) Received: from rack-server-1.dalakolonin.se (unknown [172.17.0.1]) by zimbra.dalakolonin.se (Postfix) with ESMTPSA id 888C88EBB9; Sun, 19 Mar 2023 22:39:20 +0000 (UTC) From: =?utf-8?q?Patrik_Dahlstr=C3=B6m?= To: linux-iio@vger.kernel.org Cc: linux-kernel@vger.kernel.org, letux-kernel@openphoenux.org, kernel@pyra-handheld.com, pgoudagunta@nvidia.com, hns@goldelico.com, jic23@kernel.org, lars@metafoo.de, =?utf-8?q?Patrik_Dahlstr=C3=B6m?= Subject: [PATCH 2/3] iio: adc: palmas_gpadc: remove adc_wakeupX_data Date: Sun, 19 Mar 2023 23:39:07 +0100 Message-Id: <20230319223908.108540-3-risca@dalakolonin.se> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230319223908.108540-1-risca@dalakolonin.se> References: <20230319223908.108540-1-risca@dalakolonin.se> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org It does not seem to be used by anyone and having two ways to configure the same thing but for different use cases is bound to introduce bugs. This removes the special use case and leaves the generic one. It's still possible to achieve the same thing as before from userspace. Signed-off-by: Patrik Dahlström --- drivers/iio/adc/palmas_gpadc.c | 18 ------------------ include/linux/mfd/palmas.h | 2 -- 2 files changed, 20 deletions(-) diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c index 84c6e3b66205..419d7db51345 100644 --- a/drivers/iio/adc/palmas_gpadc.c +++ b/drivers/iio/adc/palmas_gpadc.c @@ -948,18 +948,6 @@ static int palmas_gpadc_probe(struct platform_device *pdev) "request auto1 irq %d failed\n", adc->irq_auto_1); - if (gpadc_pdata->adc_wakeup1_data) { - memcpy(&adc->wakeup1_data, gpadc_pdata->adc_wakeup1_data, - sizeof(adc->wakeup1_data)); - adc->wakeup1_enable = true; - } - - if (gpadc_pdata->adc_wakeup2_data) { - memcpy(&adc->wakeup2_data, gpadc_pdata->adc_wakeup2_data, - sizeof(adc->wakeup2_data)); - adc->wakeup2_enable = true; - } - adc->event0.channel = -1; adc->event0.direction = IIO_EV_DIR_NONE; adc->event1.channel = -1; @@ -1004,12 +992,6 @@ static int palmas_gpadc_probe(struct platform_device *pdev) } device_set_wakeup_capable(&pdev->dev, 1); - if (adc->wakeup1_enable || adc->wakeup2_enable) { - ret = palmas_adc_wakeup_configure(adc); - if (ret) - return ret; - device_wakeup_enable(&pdev->dev); - } ret = devm_add_action_or_reset(&pdev->dev, palmas_disable_wakeup, adc); diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h index 1e61c7e9f50d..dc79d5e2d680 100644 --- a/include/linux/mfd/palmas.h +++ b/include/linux/mfd/palmas.h @@ -153,8 +153,6 @@ struct palmas_gpadc_platform_data { int start_polarity; int auto_conversion_period_ms; - struct palmas_adc_wakeup_property *adc_wakeup1_data; - struct palmas_adc_wakeup_property *adc_wakeup2_data; }; struct palmas_reg_init { From patchwork Sun Mar 19 22:39:08 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Patrik_Dahlstr=C3=B6m?= X-Patchwork-Id: 13180648 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D296EC76196 for ; Sun, 19 Mar 2023 22:39:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229997AbjCSWjm convert rfc822-to-8bit (ORCPT ); Sun, 19 Mar 2023 18:39:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33250 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229779AbjCSWjk (ORCPT ); Sun, 19 Mar 2023 18:39:40 -0400 Received: from pio-pvt-msa1.bahnhof.se (pio-pvt-msa1.bahnhof.se [79.136.2.40]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D28E21B542; Sun, 19 Mar 2023 15:39:37 -0700 (PDT) Received: from localhost (localhost [127.0.0.1]) by pio-pvt-msa1.bahnhof.se (Postfix) with ESMTP id 8C3A23F683; Sun, 19 Mar 2023 23:39:35 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at bahnhof.se Received: from pio-pvt-msa1.bahnhof.se ([127.0.0.1]) by localhost (pio-pvt-msa1.bahnhof.se [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id OYmxcAaU6aKO; Sun, 19 Mar 2023 23:39:34 +0100 (CET) Received: by pio-pvt-msa1.bahnhof.se (Postfix) with ESMTPA id 6840F3F55C; Sun, 19 Mar 2023 23:39:34 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by zimbra.dalakolonin.se (Postfix) with ESMTP id 9FEE88EBD6; Sun, 19 Mar 2023 22:39:27 +0000 (UTC) Received: from zimbra.dalakolonin.se ([127.0.0.1]) by localhost (zimbra.dalakolonin.se [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id WrE8dZEpIUYh; Sun, 19 Mar 2023 22:39:22 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by zimbra.dalakolonin.se (Postfix) with ESMTP id 133008EBCF; Sun, 19 Mar 2023 22:39:22 +0000 (UTC) X-Virus-Scanned: amavisd-new at dalakolonin.se Received: from zimbra.dalakolonin.se ([127.0.0.1]) by localhost (zimbra.dalakolonin.se [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id crPBhBBIioQm; Sun, 19 Mar 2023 22:39:22 +0000 (UTC) Received: from rack-server-1.dalakolonin.se (unknown [172.17.0.1]) by zimbra.dalakolonin.se (Postfix) with ESMTPSA id A9E248EBC8; Sun, 19 Mar 2023 22:39:21 +0000 (UTC) From: =?utf-8?q?Patrik_Dahlstr=C3=B6m?= To: linux-iio@vger.kernel.org Cc: linux-kernel@vger.kernel.org, letux-kernel@openphoenux.org, kernel@pyra-handheld.com, pgoudagunta@nvidia.com, hns@goldelico.com, jic23@kernel.org, lars@metafoo.de, =?utf-8?q?Patrik_Dahlstr=C3=B6m?= Subject: [PATCH 3/3] iio: adc: palmas_gpadc: remove palmas_adc_wakeup_property Date: Sun, 19 Mar 2023 23:39:08 +0100 Message-Id: <20230319223908.108540-4-risca@dalakolonin.se> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230319223908.108540-1-risca@dalakolonin.se> References: <20230319223908.108540-1-risca@dalakolonin.se> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org This struct contain essentially the same information as palmas_adc_event and palmas_gpadc_thresholds combined, but with more ambiguity: the code decided whether to trigger on rising or falling edge based on the high threshold being non-zero. Since its use in platform data has now been removed, we can remove it entirely. Lastly, the use case for waking up the cpu from sleep mode when a threshold has been passed is no longer the primary use for events so all code is changed to say "event" instead of "wakeup". Signed-off-by: Patrik Dahlström --- drivers/iio/adc/palmas_gpadc.c | 94 +++++++++++++--------------------- include/linux/mfd/palmas.h | 6 --- 2 files changed, 36 insertions(+), 64 deletions(-) diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c index 419d7db51345..042b68f29444 100644 --- a/drivers/iio/adc/palmas_gpadc.c +++ b/drivers/iio/adc/palmas_gpadc.c @@ -122,10 +122,8 @@ struct palmas_gpadc { int irq_auto_1; struct palmas_gpadc_info *adc_info; struct completion conv_completion; - struct palmas_adc_wakeup_property wakeup1_data; - struct palmas_adc_wakeup_property wakeup2_data; - bool wakeup1_enable; - bool wakeup2_enable; + bool event0_enable; + bool event1_enable; int auto_conversion_period; struct mutex lock; struct palmas_adc_event event0; @@ -592,50 +590,26 @@ static int palmas_gpadc_read_event_config(struct iio_dev *indio_dev, return ret; } -static void palmas_adc_event_to_wakeup(struct palmas_gpadc *adc, - struct palmas_adc_event *ev, - struct palmas_adc_wakeup_property *wakeup) -{ - wakeup->adc_channel_number = ev->channel; - if (ev->direction == IIO_EV_DIR_RISING) { - wakeup->adc_low_threshold = 0; - wakeup->adc_high_threshold = - palmas_gpadc_get_high_threshold_raw(adc, &adc->event0); - } - else { - wakeup->adc_low_threshold = - palmas_gpadc_get_low_threshold_raw(adc, &adc->event0); - wakeup->adc_high_threshold = 0; - } -} - -static int palmas_adc_wakeup_configure(struct palmas_gpadc *adc); -static int palmas_adc_wakeup_reset(struct palmas_gpadc *adc); +static int palmas_adc_events_configure(struct palmas_gpadc *adc); +static int palmas_adc_events_reset(struct palmas_gpadc *adc); static int palmas_gpadc_reconfigure_event_channels(struct palmas_gpadc *adc) { - bool was_enabled = adc->wakeup1_enable || adc->wakeup2_enable; + bool was_enabled = adc->event0_enable || adc->event1_enable; bool enable; - adc->wakeup1_enable = adc->event0.channel == -1 ? false : true; - adc->wakeup2_enable = adc->event1.channel == -1 ? false : true; + adc->event0_enable = adc->event0.channel == -1 ? false : true; + adc->event1_enable = adc->event1.channel == -1 ? false : true; - enable = adc->wakeup1_enable || adc->wakeup2_enable; + enable = adc->event0_enable || adc->event1_enable; if (!was_enabled && enable) device_wakeup_enable(adc->dev); else if (was_enabled && !enable) device_wakeup_disable(adc->dev); - if (!enable) - return palmas_adc_wakeup_reset(adc); - - // adjust levels - if (adc->wakeup1_enable) - palmas_adc_event_to_wakeup(adc, &adc->event0, &adc->wakeup1_data); - if (adc->wakeup2_enable) - palmas_adc_event_to_wakeup(adc, &adc->event1, &adc->wakeup2_data); - - return palmas_adc_wakeup_configure(adc); + return enable ? + palmas_adc_events_configure(adc) : + palmas_adc_events_reset(adc); } static int palmas_gpadc_enable_event_config(struct palmas_gpadc *adc, @@ -864,12 +838,14 @@ static int palmas_gpadc_get_adc_dt_data(struct platform_device *pdev, return 0; } -static void palmas_disable_wakeup(void *data) +static void palmas_disable_events(void *data) { struct palmas_gpadc *adc = data; - if (adc->wakeup1_enable || adc->wakeup2_enable) + if (adc->event0_enable || adc->event1_enable) { + palmas_adc_events_reset(adc); device_wakeup_disable(adc->dev); + } } static int palmas_gpadc_probe(struct platform_device *pdev) @@ -993,7 +969,7 @@ static int palmas_gpadc_probe(struct platform_device *pdev) device_set_wakeup_capable(&pdev->dev, 1); ret = devm_add_action_or_reset(&pdev->dev, - palmas_disable_wakeup, + palmas_disable_events, adc); if (ret) return ret; @@ -1001,7 +977,7 @@ static int palmas_gpadc_probe(struct platform_device *pdev) return 0; } -static int palmas_adc_wakeup_configure(struct palmas_gpadc *adc) +static int palmas_adc_events_configure(struct palmas_gpadc *adc) { int adc_period, conv; int i; @@ -1027,16 +1003,18 @@ static int palmas_adc_wakeup_configure(struct palmas_gpadc *adc) } conv = 0; - if (adc->wakeup1_enable) { + if (adc->event0_enable) { + struct palmas_adc_event *ev = &adc->event0; int polarity; - ch0 = adc->wakeup1_data.adc_channel_number; + ch0 = ev->channel; conv |= PALMAS_GPADC_AUTO_CTRL_AUTO_CONV0_EN; - if (adc->wakeup1_data.adc_high_threshold > 0) { - thres = adc->wakeup1_data.adc_high_threshold; + + if (ev->direction == IIO_EV_DIR_RISING) { + thres = palmas_gpadc_get_high_threshold_raw(adc, ev); polarity = 0; } else { - thres = adc->wakeup1_data.adc_low_threshold; + thres = palmas_gpadc_get_low_threshold_raw(adc, ev); polarity = PALMAS_GPADC_THRES_CONV0_MSB_THRES_CONV0_POL; } @@ -1058,16 +1036,18 @@ static int palmas_adc_wakeup_configure(struct palmas_gpadc *adc) } } - if (adc->wakeup2_enable) { + if (adc->event1_enable) { + struct palmas_adc_event *ev = &adc->event1; int polarity; - ch1 = adc->wakeup2_data.adc_channel_number; + ch1 = ev->channel; conv |= PALMAS_GPADC_AUTO_CTRL_AUTO_CONV1_EN; - if (adc->wakeup2_data.adc_high_threshold > 0) { - thres = adc->wakeup2_data.adc_high_threshold; + + if (ev->direction == IIO_EV_DIR_RISING) { + thres = palmas_gpadc_get_high_threshold_raw(adc, ev); polarity = 0; } else { - thres = adc->wakeup2_data.adc_low_threshold; + thres = palmas_gpadc_get_low_threshold_raw(adc, ev); polarity = PALMAS_GPADC_THRES_CONV1_MSB_THRES_CONV1_POL; } @@ -1106,7 +1086,7 @@ static int palmas_adc_wakeup_configure(struct palmas_gpadc *adc) return ret; } -static int palmas_adc_wakeup_reset(struct palmas_gpadc *adc) +static int palmas_adc_events_reset(struct palmas_gpadc *adc) { int ret; @@ -1128,15 +1108,14 @@ static int palmas_gpadc_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct palmas_gpadc *adc = iio_priv(indio_dev); - int ret; if (!device_may_wakeup(dev)) return 0; - if (adc->wakeup1_enable) + if (adc->event0_enable) enable_irq_wake(adc->irq_auto_0); - if (adc->wakeup2_enable) + if (adc->event1_enable) enable_irq_wake(adc->irq_auto_1); return 0; @@ -1146,15 +1125,14 @@ static int palmas_gpadc_resume(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct palmas_gpadc *adc = iio_priv(indio_dev); - int ret; if (!device_may_wakeup(dev)) return 0; - if (adc->wakeup1_enable) + if (adc->event0_enable) disable_irq_wake(adc->irq_auto_0); - if (adc->wakeup2_enable) + if (adc->event1_enable) disable_irq_wake(adc->irq_auto_1); return 0; diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h index dc79d5e2d680..55f22adb1a9e 100644 --- a/include/linux/mfd/palmas.h +++ b/include/linux/mfd/palmas.h @@ -129,12 +129,6 @@ struct palmas_pmic_driver_data { struct regulator_config config); }; -struct palmas_adc_wakeup_property { - int adc_channel_number; - int adc_high_threshold; - int adc_low_threshold; -}; - struct palmas_gpadc_platform_data { /* Channel 3 current source is only enabled during conversion */ int ch3_current; /* 0: off; 1: 10uA; 2: 400uA; 3: 800 uA */