From patchwork Tue Mar 28 17:30:12 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Icenowy Zheng X-Patchwork-Id: 9650291 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 8CB7B602C8 for ; Tue, 28 Mar 2017 17:32:18 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 70FD722BF1 for ; Tue, 28 Mar 2017 17:32:18 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6570827F90; Tue, 28 Mar 2017 17:32:18 +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=-1.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 9C72022BF1 for ; Tue, 28 Mar 2017 17:32:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=ZkYld+bOGc40se/Auu8c1w2kHz+vcI7Qk8dPeW6LZxo=; b=SB0/DDLi+p7mFA+18jsMZ81ilY iRKouHWz2udGn5PDGHEXhNrGuiHv98g43vrDnSMv/fFIsIzJ/5AA+pJ0kvwvwNX+KLeMLEVNvoDEy wIW+c/J6Nzb+j76EULd/ggzs5xfvxJCppWeAZAYZsO2VQcK8Kh3js2b6u79K7mqe1dhHte+zEei91 m3Aw6n9HNtl70gzOWeSMRg3Fg2sBjxa1MT/AUO9w8AZDa9hQF5UYaYLHJwfsG+IF48LaSSkKXyR2I FQAdMblI/qQsamDehnXamlIf1Y/zEKReztBIJW5Fpcnrm5JOH/qQ6ze9rz56kWuCV+jdBZzLOVIUd st3Br3Hg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1csuyc-0001vj-4r; Tue, 28 Mar 2017 17:32:14 +0000 Received: from burlywood.ash.relay.mailchannels.net ([23.83.222.26]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1csuy7-0001Im-70 for linux-arm-kernel@lists.infradead.org; Tue, 28 Mar 2017 17:31:46 +0000 X-Sender-Id: lmn-tzduiowcrqmw|x-authsender|icenowy@aosc.io Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 17C3E124222; Tue, 28 Mar 2017 17:31:12 +0000 (UTC) Received: from hermes.aosc.io (unknown [100.96.137.101]) by relay.mailchannels.net (Postfix) with ESMTPA id 2145D123105; Tue, 28 Mar 2017 17:31:05 +0000 (UTC) X-Sender-Id: lmn-tzduiowcrqmw|x-authsender|icenowy@aosc.io Received: from hermes.aosc.io (hermes.aosc.io [172.20.63.242]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384) by 0.0.0.0:2500 (trex/5.7.37); Tue, 28 Mar 2017 17:31:12 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: lmn-tzduiowcrqmw|x-authsender|icenowy@aosc.io X-MailChannels-Auth-Id: lmn-TZDUIOWCRQMW X-Lonely-Cooing: 76e4e1720e2a0bc0_1490722265609_1552046931 X-MC-Loop-Signature: 1490722265609:3255879031 X-MC-Ingress-Time: 1490722265609 Received: from localhost.localdomain (unknown [120.236.174.154]) (Authenticated sender: icenowy@aosc.io) by hermes.aosc.io (Postfix) with ESMTPSA id A67E180312; Tue, 28 Mar 2017 17:30:53 +0000 (UTC) From: Icenowy Zheng To: Lee Jones , Rob Herring , Maxime Ripard , Chen-Yu Tsai , Jonathan Cameron , Zhang Rui , Quentin Schulz Subject: [RFC PATCH 2/3] iio: adc: sun4i-gpadc-iio: add support for H3 thermal sensor Date: Wed, 29 Mar 2017 01:30:12 +0800 Message-Id: <20170328173013.16539-3-icenowy@aosc.io> X-Mailer: git-send-email 2.12.0 In-Reply-To: <20170328173013.16539-1-icenowy@aosc.io> References: <20170328173013.16539-1-icenowy@aosc.io> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170328_103143_958444_C248A7E8 X-CRM114-Status: GOOD ( 22.01 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: devicetree@vger.kernel.org, linux-pm@vger.kernel.org, linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Icenowy Zheng MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP This adds support for the Allwinner H3 thermal sensor. Allwinner H3 has a thermal sensor like the one in A33, but have its registers nearly all re-arranged, sample clock moved to CCU and a pair of bus clock and reset added. It's also the base of newer SoCs' thermal sensors. An option is added to gpadc_data struct, to indicate whether this device is a new-generation Allwinner thermal sensor. The thermal sensors on A64 and H5 is like the one on H3, but with of course different formula factors. Signed-off-by: Icenowy Zheng --- drivers/iio/adc/sun4i-gpadc-iio.c | 130 ++++++++++++++++++++++++++++++++------ include/linux/mfd/sun4i-gpadc.h | 33 +++++++++- 2 files changed, 141 insertions(+), 22 deletions(-) diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c index 74705aa37982..7512b1cae877 100644 --- a/drivers/iio/adc/sun4i-gpadc-iio.c +++ b/drivers/iio/adc/sun4i-gpadc-iio.c @@ -22,6 +22,7 @@ * shutdown for not being used. */ +#include #include #include #include @@ -31,6 +32,7 @@ #include #include #include +#include #include #include @@ -56,6 +58,7 @@ struct gpadc_data { unsigned int tp_adc_select; unsigned int (*adc_chan_select)(unsigned int chan); unsigned int adc_chan_mask; + bool gen2_ths; }; static const struct gpadc_data sun4i_gpadc_data = { @@ -88,7 +91,20 @@ static const struct gpadc_data sun6i_gpadc_data = { static const struct gpadc_data sun8i_a33_gpadc_data = { .temp_offset = -1662, .temp_scale = 162, - .tp_mode_en = SUN8I_GPADC_CTRL1_CHOP_TEMP_EN, + .tp_mode_en = SUN8I_A23_GPADC_CTRL1_CHOP_TEMP_EN, +}; + +static const struct gpadc_data sun8i_h3_gpadc_data = { + /* + * The original formula on the datasheet seems to be wrong. + * These factors are calculated based on the formula in the BSP + * kernel, which is originally Tem = 217 - (T / 8.253), in which Tem + * is the temperature in Celsius degree and T is the raw value + * from the sensor. + */ + .temp_offset = -1791, + .temp_scale = -121, + .gen2_ths = true, }; struct sun4i_gpadc_iio { @@ -103,6 +119,9 @@ struct sun4i_gpadc_iio { atomic_t ignore_temp_data_irq; const struct gpadc_data *data; bool no_irq; + struct clk *ths_bus_clk; + struct clk *ths_clk; + struct reset_control *reset; /* prevents concurrent reads of temperature and ADC */ struct mutex mutex; }; @@ -274,7 +293,11 @@ static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val) if (info->no_irq) { pm_runtime_get_sync(indio_dev->dev.parent); - regmap_read(info->regmap, SUN4I_GPADC_TEMP_DATA, val); + if (info->data->gen2_ths) + regmap_read(info->regmap, SUN8I_H3_GPADC_TEMP_DATA, + val); + else + regmap_read(info->regmap, SUN4I_GPADC_TEMP_DATA, val); pm_runtime_mark_last_busy(indio_dev->dev.parent); pm_runtime_put_autosuspend(indio_dev->dev.parent); @@ -386,10 +409,15 @@ static int sun4i_gpadc_runtime_suspend(struct device *dev) { struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev)); - /* Disable the ADC on IP */ - regmap_write(info->regmap, SUN4I_GPADC_CTRL1, 0); - /* Disable temperature sensor on IP */ - regmap_write(info->regmap, SUN4I_GPADC_TPR, 0); + if (info->data->gen2_ths) { + /* Disable temperature sensor */ + regmap_write(info->regmap, SUN8I_H3_GPADC_CTRL2, 0); + } else { + /* Disable the ADC on IP */ + regmap_write(info->regmap, SUN4I_GPADC_CTRL1, 0); + /* Disable temperature sensor on IP */ + regmap_write(info->regmap, SUN4I_GPADC_TPR, 0); + } return 0; } @@ -398,19 +426,36 @@ static int sun4i_gpadc_runtime_resume(struct device *dev) { struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev)); - /* clkin = 6MHz */ - regmap_write(info->regmap, SUN4I_GPADC_CTRL0, - SUN4I_GPADC_CTRL0_ADC_CLK_DIVIDER(2) | - SUN4I_GPADC_CTRL0_FS_DIV(7) | - SUN4I_GPADC_CTRL0_T_ACQ(63)); - regmap_write(info->regmap, SUN4I_GPADC_CTRL1, info->data->tp_mode_en); - regmap_write(info->regmap, SUN4I_GPADC_CTRL3, - SUN4I_GPADC_CTRL3_FILTER_EN | - SUN4I_GPADC_CTRL3_FILTER_TYPE(1)); - /* period = SUN4I_GPADC_TPR_TEMP_PERIOD * 256 * 16 / clkin; ~0.6s */ - regmap_write(info->regmap, SUN4I_GPADC_TPR, - SUN4I_GPADC_TPR_TEMP_ENABLE | - SUN4I_GPADC_TPR_TEMP_PERIOD(800)); + if (info->data->gen2_ths) { + regmap_write(info->regmap, SUN8I_H3_GPADC_CTRL2, + SUN8I_H3_GPADC_CTRL2_TEMP_SENSE_EN | + SUN8I_H3_GPADC_CTRL2_T_ACQ1(31)); + regmap_write(info->regmap, SUN4I_GPADC_CTRL0, + SUN4I_GPADC_CTRL0_T_ACQ(31)); + regmap_write(info->regmap, SUN8I_H3_GPADC_CTRL3, + SUN4I_GPADC_CTRL3_FILTER_EN | + SUN4I_GPADC_CTRL3_FILTER_TYPE(1)); + regmap_write(info->regmap, SUN8I_H3_GPADC_INTC, + SUN8I_H3_GPADC_INTC_TEMP_PERIOD(800)); + } else { + /* clkin = 6MHz */ + regmap_write(info->regmap, SUN4I_GPADC_CTRL0, + SUN4I_GPADC_CTRL0_ADC_CLK_DIVIDER(2) | + SUN4I_GPADC_CTRL0_FS_DIV(7) | + SUN4I_GPADC_CTRL0_T_ACQ(63)); + regmap_write(info->regmap, SUN4I_GPADC_CTRL1, + info->data->tp_mode_en); + regmap_write(info->regmap, SUN4I_GPADC_CTRL3, + SUN4I_GPADC_CTRL3_FILTER_EN | + SUN4I_GPADC_CTRL3_FILTER_TYPE(1)); + /* + * period = SUN4I_GPADC_TPR_TEMP_PERIOD * 256 * 16 / clkin; + * ~0.6s + */ + regmap_write(info->regmap, SUN4I_GPADC_TPR, + SUN4I_GPADC_TPR_TEMP_ENABLE | + SUN4I_GPADC_TPR_TEMP_PERIOD(800)); + } return 0; } @@ -494,6 +539,10 @@ static const struct of_device_id sun4i_gpadc_of_id[] = { .compatible = "allwinner,sun8i-a33-ths", .data = &sun8i_a33_gpadc_data, }, + { + .compatible = "allwinner,sun8i-h3-ths", + .data = &sun8i_h3_gpadc_data, + }, { /* sentinel */ } }; @@ -529,6 +578,43 @@ static int sun4i_gpadc_probe_dt(struct platform_device *pdev, return ret; } + if (info->data->gen2_ths) { + info->reset = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(info->reset)) { + ret = PTR_ERR(info->reset); + return ret; + } + + ret = reset_control_deassert(info->reset); + if (ret) + return ret; + + info->ths_bus_clk = devm_clk_get(&pdev->dev, "bus"); + if (IS_ERR(info->ths_bus_clk)) { + ret = PTR_ERR(info->ths_bus_clk); + return ret; + } + + ret = clk_prepare_enable(info->ths_bus_clk); + if (ret) + return ret; + + info->ths_clk = devm_clk_get(&pdev->dev, "ths"); + if (IS_ERR(info->ths_clk)) { + ret = PTR_ERR(info->ths_clk); + return ret; + } + + /* Running at 6MHz */ + ret = clk_set_rate(info->ths_clk, 6000000); + if (ret) + return ret; + + ret = clk_prepare_enable(info->ths_clk); + if (ret) + return ret; + } + if (!IS_ENABLED(CONFIG_THERMAL_OF)) return 0; @@ -691,6 +777,12 @@ static int sun4i_gpadc_remove(struct platform_device *pdev) if (!info->no_irq && IS_ENABLED(CONFIG_THERMAL_OF)) iio_map_array_unregister(indio_dev); + if (info->data->gen2_ths) { + clk_disable_unprepare(info->ths_clk); + clk_disable_unprepare(info->ths_bus_clk); + reset_control_deassert(info->reset); + } + return 0; } diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h index 139872c2e0fe..f794a2988a93 100644 --- a/include/linux/mfd/sun4i-gpadc.h +++ b/include/linux/mfd/sun4i-gpadc.h @@ -38,9 +38,12 @@ #define SUN6I_GPADC_CTRL1_ADC_CHAN_SELECT(x) (GENMASK(3, 0) & BIT(x)) #define SUN6I_GPADC_CTRL1_ADC_CHAN_MASK GENMASK(3, 0) -/* TP_CTRL1 bits for sun8i SoCs */ -#define SUN8I_GPADC_CTRL1_CHOP_TEMP_EN BIT(8) -#define SUN8I_GPADC_CTRL1_GPADC_CALI_EN BIT(7) +/* TP_CTRL1 bits for sun8i A23/A33 SoCs */ +#define SUN8I_A23_GPADC_CTRL1_CHOP_TEMP_EN BIT(8) +#define SUN8I_A23_GPADC_CTRL1_GPADC_CALI_EN BIT(7) + +/* TP_CTRL1 bits for SoCs after H3 */ +#define SUN8I_H3_GPADC_CTRL1_GPADC_CALI_EN BIT(17) #define SUN4I_GPADC_CTRL2 0x08 @@ -49,7 +52,17 @@ #define SUN4I_GPADC_CTRL2_PRE_MEA_EN BIT(24) #define SUN4I_GPADC_CTRL2_PRE_MEA_THRE_CNT(x) (GENMASK(23, 0) & (x)) +#define SUN8I_H3_GPADC_CTRL2 0x40 + +#define SUN8I_H3_GPADC_CTRL2_TEMP_SENSE_EN BIT(0) +#define SUN8I_H3_GPADC_CTRL2_T_ACQ1(x) ((GENMASK(15, 0) * (x)) << 16) + #define SUN4I_GPADC_CTRL3 0x0c +/* + * This register is named "Average filter Control Register" in H3 Datasheet, + * but the register's definition is the same as the old CTRL3 register. + */ +#define SUN8I_H3_GPADC_CTRL3 0x70 #define SUN4I_GPADC_CTRL3_FILTER_EN BIT(2) #define SUN4I_GPADC_CTRL3_FILTER_TYPE(x) (GENMASK(1, 0) & (x)) @@ -71,6 +84,13 @@ #define SUN4I_GPADC_INT_FIFOC_TP_UP_IRQ_EN BIT(1) #define SUN4I_GPADC_INT_FIFOC_TP_DOWN_IRQ_EN BIT(0) +#define SUN8I_H3_GPADC_INTC 0x44 + +#define SUN8I_H3_GPADC_INTC_TEMP_PERIOD(x) ((GENMASK(19, 0) & (x)) << 12) +#define SUN8I_H3_GPADC_INTC_TEMP_DATA BIT(8) +#define SUN8I_H3_GPADC_INTC_TEMP_SHUT BIT(4) +#define SUN8I_H3_GPADC_INTC_TEMP_ALARM BIT(0) + #define SUN4I_GPADC_INT_FIFOS 0x14 #define SUN4I_GPADC_INT_FIFOS_TEMP_DATA_PENDING BIT(18) @@ -80,9 +100,16 @@ #define SUN4I_GPADC_INT_FIFOS_TP_UP_PENDING BIT(1) #define SUN4I_GPADC_INT_FIFOS_TP_DOWN_PENDING BIT(0) +#define SUN8I_H3_GPADC_INTS 0x44 + +#define SUN8I_H3_GPADC_INTS_TEMP_DATA BIT(8) +#define SUN8I_H3_GPADC_INTS_TEMP_SHUT BIT(4) +#define SUN8I_H3_GPADC_INTS_TEMP_ALARM BIT(0) + #define SUN4I_GPADC_CDAT 0x1c #define SUN4I_GPADC_TEMP_DATA 0x20 #define SUN4I_GPADC_DATA 0x24 +#define SUN8I_H3_GPADC_TEMP_DATA 0x80 #define SUN4I_GPADC_IRQ_FIFO_DATA 0 #define SUN4I_GPADC_IRQ_TEMP_DATA 1