From patchwork Fri Aug 9 11:01:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Krzysztof Kozlowski X-Patchwork-Id: 818128 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 alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id EDEDFC52D7C for ; Fri, 9 Aug 2024 11:14:45 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 732BBEF2; Fri, 9 Aug 2024 13:14:33 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 732BBEF2 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1723202083; bh=MUOJttNLDDkaf3vn9kxvM207x74kpVe47iGW1tUIkIQ=; h=From:To:Cc:Subject:Date:List-Id:List-Archive:List-Help:List-Owner: List-Post:List-Subscribe:List-Unsubscribe:From; b=GWJwLUE5uvOteRSVtnXxMJdBBm1lI15MZ54R1dDj8N+IZRzOXCpEP9vFP/BDKmpML a6dzpkIzS7w8muE4PQPzjm4eVOUpVN6f9e7qxl/a6087PuJYw9D+bcYQwknn3HWIZl sRLnv7ChyoKj67sloQSTd/fcCXBH42pDzJlgGn1Q= Received: by alsa1.perex.cz (Postfix, from userid 50401) id D0932F805A8; Fri, 9 Aug 2024 13:14:11 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 4091BF805B5; Fri, 9 Aug 2024 13:14:11 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 251ADF800E3; Fri, 9 Aug 2024 13:06:39 +0200 (CEST) Received: from mail-wr1-x429.google.com (mail-wr1-x429.google.com [IPv6:2a00:1450:4864:20::429]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 70D5BF800E3 for ; Fri, 9 Aug 2024 13:01:29 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 70D5BF800E3 Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key, unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256 header.s=google header.b=LvfAVZsh Received: by mail-wr1-x429.google.com with SMTP id ffacd0b85a97d-3684407b2deso1017626f8f.1 for ; Fri, 09 Aug 2024 04:01:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1723201288; x=1723806088; darn=alsa-project.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=/682q/IgmSx1ugjwpcrW1fYYFoT2Yei89ggcZ5WWfo8=; b=LvfAVZsh2zIkM7de/0Twx51bFexGcfi5Lyh0Hmp3K80W9YcAfl10deZ37SGtL6VzSM 0Ni744luZ2J6S3MTay6Ud62xq3kfrToWlJhn+2+poy0ZouTmklL1fW6TrXnajvnbId2U O2pRD+/ZtBEiuxKSxzVour60KjjZFppOeYWIl5uQ82A9HIctSPJYoh1eprc6Ns4ekxBs NM6Z618qneD/rwnlxzy0KTwpL6aiW1u2WuIVrTIDROmuDSNyluN8mtbkZVva4UlEe5Fg Ewxvn964rpYXubvxyHDCCAT3hanme3yLOpvEQhUhcrFAp8UTZibxOifwKTsrOdUotBdw f3iQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1723201288; x=1723806088; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=/682q/IgmSx1ugjwpcrW1fYYFoT2Yei89ggcZ5WWfo8=; b=NedtkGhtNe3oi3AXCVu38dhTxmZ8lTwAojZMPPdnluKMdsmC0YX63zIokhFqRjQqlS xTy0RQj+huWS0+6ethtBIbk8VmVce66kx3MYIQL3HuH+c2AWZGkFuUMP4u2tUOMgteor kxdpMuK4iWvgOj8vhSycFuLP+mfSJWGEoOgxXxPx14DuPycYG5jVwry73KwQsKLznnmf 36gH1HtYc3FQCtEs4h/AvDktDUkzvqPqDz63bn8JckPXb7CpPAVZemNszZdUPJndKetF OkPFJCzm94/TYTLabcr4pXahY62A3flZoI7aVj28nNtRsv4UdBLJOZd4CVGW6+9J9w9l r3KA== X-Forwarded-Encrypted: i=1; AJvYcCWWWZABsLQdBDVLssSyCcMKnIPGxb2DM2u7OfPNZPLKdX+NFbguOb7JzZZPw691owAYlCx9rKrHjiY5tGSLrCZouDm1l40V4oQObwA= X-Gm-Message-State: AOJu0YznbSIwIeEk14El+jcxQpgr77RHsud9Wpp2iaaLpdaX6/+JJoEs 08Vk3mHnb6aDEzlEXm4fshvF9P1lffZuLQZ4Ma7Kh1VLthIr/VV5Cc45uSF0T2o= X-Google-Smtp-Source: AGHT+IEMw0S9h0YIYl4LyxIuHNAP7T9PX2ZjGuz2Ky4aelpGhhnCl3Hs3qzr8diKaTFhAHA9AO9+OA== X-Received: by 2002:a5d:5f91:0:b0:367:8a84:7427 with SMTP id ffacd0b85a97d-36d5de93557mr1073255f8f.2.1723201288119; Fri, 09 Aug 2024 04:01:28 -0700 (PDT) Received: from krzk-bin.. ([178.197.219.137]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-36d340acfdasm1815992f8f.13.2024.08.09.04.01.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 09 Aug 2024 04:01:27 -0700 (PDT) From: Krzysztof Kozlowski To: Srinivas Kandagatla , Banajit Goswami , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Jean Delvare , Guenter Roeck , alsa-devel@alsa-project.org, linux-arm-msm@vger.kernel.org, linux-sound@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org Cc: Krzysztof Kozlowski Subject: [PATCH v3] ASoC: codecs: wsa884x: Implement temperature reading and hwmon Date: Fri, 9 Aug 2024 13:01:22 +0200 Message-ID: <20240809110122.137761-1-krzysztof.kozlowski@linaro.org> X-Mailer: git-send-email 2.43.0 MIME-Version: 1.0 Message-ID-Hash: 75336KGZ62QHHFSRM2JUOMUR4P7YA4LL X-Message-ID-Hash: 75336KGZ62QHHFSRM2JUOMUR4P7YA4LL X-MailFrom: krzysztof.kozlowski@linaro.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.9 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Read temperature of the speaker and expose it via hwmon interface, which will be later used during calibration of speaker protection algorithms. Signed-off-by: Krzysztof Kozlowski --- Changes in v3: 1. Replace Kconfig HWMON dependency in favor of IS_REACHABLE(CONFIG_HWMON) which solves Kernel Test Robot warning for !HWMON and HWMON=y && WSA884x=m Changes in v2: 1. Add missing dependency on HWMON for y!=m builds (Kernel Test Robot report: undefined reference to `devm_hwmon_device_register_with_info'). --- sound/soc/codecs/wsa884x.c | 201 +++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c index 8db1380d1f10..86df5152c547 100644 --- a/sound/soc/codecs/wsa884x.c +++ b/sound/soc/codecs/wsa884x.c @@ -5,11 +5,14 @@ */ #include +#include #include #include +#include #include #include #include +#include #include #include #include @@ -301,8 +304,28 @@ #define WSA884X_PA_FSM_MSK1 (WSA884X_DIG_CTRL0_BASE + 0x3b) #define WSA884X_PA_FSM_BYP_CTL (WSA884X_DIG_CTRL0_BASE + 0x3c) #define WSA884X_PA_FSM_BYP0 (WSA884X_DIG_CTRL0_BASE + 0x3d) +#define WSA884X_PA_FSM_BYP0_DC_CAL_EN_MASK 0x01 +#define WSA884X_PA_FSM_BYP0_DC_CAL_EN_SHIFT 0 +#define WSA884X_PA_FSM_BYP0_CLK_WD_EN_MASK 0x02 +#define WSA884X_PA_FSM_BYP0_CLK_WD_EN_SHIFT 1 +#define WSA884X_PA_FSM_BYP0_BG_EN_MASK 0x04 +#define WSA884X_PA_FSM_BYP0_BG_EN_SHIFT 2 +#define WSA884X_PA_FSM_BYP0_BOOST_EN_MASK 0x08 +#define WSA884X_PA_FSM_BYP0_BOOST_EN_SHIFT 3 +#define WSA884X_PA_FSM_BYP0_PA_EN_MASK 0x10 +#define WSA884X_PA_FSM_BYP0_PA_EN_SHIFT 4 +#define WSA884X_PA_FSM_BYP0_D_UNMUTE_MASK 0x20 +#define WSA884X_PA_FSM_BYP0_D_UNMUTE_SHIFT 5 +#define WSA884X_PA_FSM_BYP0_SPKR_PROT_EN_MASK 0x40 +#define WSA884X_PA_FSM_BYP0_SPKR_PROT_EN_SHIFT 6 +#define WSA884X_PA_FSM_BYP0_TSADC_EN_MASK 0x80 +#define WSA884X_PA_FSM_BYP0_TSADC_EN_SHIFT 7 #define WSA884X_PA_FSM_BYP1 (WSA884X_DIG_CTRL0_BASE + 0x3e) #define WSA884X_TADC_VALUE_CTL (WSA884X_DIG_CTRL0_BASE + 0x50) +#define WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK 0x01 +#define WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_SHIFT 0 +#define WSA884X_TADC_VALUE_CTL_VBAT_VALUE_RD_EN_MASK 0x02 +#define WSA884X_TADC_VALUE_CTL_VBAT_VALUE_RD_EN_SHIFT 1 #define WSA884X_TEMP_DETECT_CTL (WSA884X_DIG_CTRL0_BASE + 0x51) #define WSA884X_TEMP_DIN_MSB (WSA884X_DIG_CTRL0_BASE + 0x52) #define WSA884X_TEMP_DIN_LSB (WSA884X_DIG_CTRL0_BASE + 0x53) @@ -691,6 +714,17 @@ SNDRV_PCM_FMTBIT_S24_LE |\ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) +/* Two-point trimming for temperature calibration */ +#define WSA884X_T1_TEMP -10L +#define WSA884X_T2_TEMP 150L + +/* + * Device will report senseless data in many cases, so discard any measurements + * outside of valid range. + */ +#define WSA884X_LOW_TEMP_THRESHOLD 5 +#define WSA884X_HIGH_TEMP_THRESHOLD 45 + struct wsa884x_priv { struct regmap *regmap; struct device *dev; @@ -706,6 +740,13 @@ struct wsa884x_priv { int active_ports; int dev_mode; bool hw_init; + /* + * Protects temperature reading code (related to speaker protection) and + * fields: temperature and pa_on. + */ + struct mutex sp_lock; + unsigned int temperature; + bool pa_on; }; enum { @@ -1660,6 +1701,10 @@ static int wsa884x_spkr_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: + mutex_lock(&wsa884x->sp_lock); + wsa884x->pa_on = true; + mutex_unlock(&wsa884x->sp_lock); + wsa884x_spkr_post_pmu(component, wsa884x); snd_soc_component_write_field(component, WSA884X_PDM_WD_CTL, @@ -1671,6 +1716,10 @@ static int wsa884x_spkr_event(struct snd_soc_dapm_widget *w, snd_soc_component_write_field(component, WSA884X_PDM_WD_CTL, WSA884X_PDM_WD_CTL_PDM_WD_EN_MASK, 0x0); + + mutex_lock(&wsa884x->sp_lock); + wsa884x->pa_on = false; + mutex_unlock(&wsa884x->sp_lock); break; } @@ -1810,6 +1859,144 @@ static struct snd_soc_dai_driver wsa884x_dais[] = { }, }; +static int wsa884x_get_temp(struct wsa884x_priv *wsa884x, long *temp) +{ + unsigned int d1_msb = 0, d1_lsb = 0, d2_msb = 0, d2_lsb = 0; + unsigned int dmeas_msb = 0, dmeas_lsb = 0; + int d1, d2, dmeas; + unsigned int mask; + long val; + int ret; + + guard(mutex)(&wsa884x->sp_lock); + + if (wsa884x->pa_on) { + /* + * Reading temperature is possible only when Power Amplifier is + * off. Report last cached data. + */ + *temp = wsa884x->temperature; + return 0; + } + + ret = pm_runtime_resume_and_get(wsa884x->dev); + if (ret < 0) + return ret; + + mask = WSA884X_PA_FSM_BYP0_DC_CAL_EN_MASK | + WSA884X_PA_FSM_BYP0_CLK_WD_EN_MASK | + WSA884X_PA_FSM_BYP0_BG_EN_MASK | + WSA884X_PA_FSM_BYP0_D_UNMUTE_MASK | + WSA884X_PA_FSM_BYP0_SPKR_PROT_EN_MASK | + WSA884X_PA_FSM_BYP0_TSADC_EN_MASK; + /* + * Here and further do not care about read or update failures. + * For example, before turning on Power Amplifier for the first + * time, reading WSA884X_TEMP_DIN_MSB will always return 0. + * Instead, check if returned value is within reasonable + * thresholds. + */ + regmap_update_bits(wsa884x->regmap, WSA884X_PA_FSM_BYP0, mask, mask); + + regmap_update_bits(wsa884x->regmap, WSA884X_TADC_VALUE_CTL, + WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK, + FIELD_PREP(WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK, 0x0)); + + regmap_read(wsa884x->regmap, WSA884X_TEMP_DIN_MSB, &dmeas_msb); + regmap_read(wsa884x->regmap, WSA884X_TEMP_DIN_LSB, &dmeas_lsb); + + regmap_update_bits(wsa884x->regmap, WSA884X_TADC_VALUE_CTL, + WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK, + FIELD_PREP(WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK, 0x1)); + + regmap_read(wsa884x->regmap, WSA884X_OTP_REG_1, &d1_msb); + regmap_read(wsa884x->regmap, WSA884X_OTP_REG_2, &d1_lsb); + regmap_read(wsa884x->regmap, WSA884X_OTP_REG_3, &d2_msb); + regmap_read(wsa884x->regmap, WSA884X_OTP_REG_4, &d2_lsb); + + regmap_update_bits(wsa884x->regmap, WSA884X_PA_FSM_BYP0, mask, 0x0); + + dmeas = (((dmeas_msb & 0xff) << 0x8) | (dmeas_lsb & 0xff)) >> 0x6; + d1 = (((d1_msb & 0xff) << 0x8) | (d1_lsb & 0xff)) >> 0x6; + d2 = (((d2_msb & 0xff) << 0x8) | (d2_lsb & 0xff)) >> 0x6; + + if (d1 == d2) { + /* Incorrect data in OTP? */ + ret = -EINVAL; + goto out; + } + + val = WSA884X_T1_TEMP + (((dmeas - d1) * (WSA884X_T2_TEMP - WSA884X_T1_TEMP))/(d2 - d1)); + + dev_dbg(wsa884x->dev, "Measured temp %ld (dmeas=%d, d1=%d, d2=%d)\n", + val, dmeas, d1, d2); + + if ((val > WSA884X_LOW_TEMP_THRESHOLD) && + (val < WSA884X_HIGH_TEMP_THRESHOLD)) { + wsa884x->temperature = val; + *temp = val; + ret = 0; + } else { + ret = -EAGAIN; + } + +out: + pm_runtime_mark_last_busy(wsa884x->dev); + pm_runtime_put_autosuspend(wsa884x->dev); + + return ret; +} + +static umode_t wsa884x_hwmon_is_visible(const void *data, + enum hwmon_sensor_types type, u32 attr, + int channel) +{ + if (type != hwmon_temp) + return 0; + + switch (attr) { + case hwmon_temp_input: + return 0444; + default: + break; + } + + return 0; +} + +static int wsa884x_hwmon_read(struct device *dev, + enum hwmon_sensor_types type, + u32 attr, int channel, long *temp) +{ + int ret; + + switch (attr) { + case hwmon_temp_input: + ret = wsa884x_get_temp(dev_get_drvdata(dev), temp); + break; + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +static const struct hwmon_channel_info *const wsa884x_hwmon_info[] = { + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), + NULL +}; + +static const struct hwmon_ops wsa884x_hwmon_ops = { + .is_visible = wsa884x_hwmon_is_visible, + .read = wsa884x_hwmon_read, +}; + +static const struct hwmon_chip_info wsa884x_hwmon_chip_info = { + .ops = &wsa884x_hwmon_ops, + .info = wsa884x_hwmon_info, +}; + static void wsa884x_reset_powerdown(void *data) { struct wsa884x_priv *wsa884x = data; @@ -1866,6 +2053,8 @@ static int wsa884x_probe(struct sdw_slave *pdev, if (!wsa884x) return -ENOMEM; + mutex_init(&wsa884x->sp_lock); + for (i = 0; i < WSA884X_SUPPLIES_NUM; i++) wsa884x->supplies[i].supply = wsa884x_supply_name[i]; @@ -1923,6 +2112,18 @@ static int wsa884x_probe(struct sdw_slave *pdev, regcache_cache_only(wsa884x->regmap, true); wsa884x->hw_init = true; + if (IS_REACHABLE(CONFIG_HWMON)) { + struct device *hwmon; + + hwmon = devm_hwmon_device_register_with_info(dev, "wsa884x", + wsa884x, + &wsa884x_hwmon_chip_info, + NULL); + if (IS_ERR(hwmon)) + return dev_err_probe(dev, PTR_ERR(hwmon), + "Failed to register hwmon sensor\n"); + } + pm_runtime_set_autosuspend_delay(dev, 3000); pm_runtime_use_autosuspend(dev); pm_runtime_mark_last_busy(dev);