Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ASoC: codecs: wsa884x: Implement temperature reading and hwmon

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 <krzysztof.kozlowski@linaro.org>
Link: https://patch.msgid.link/20240809110122.137761-1-krzysztof.kozlowski@linaro.org
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Krzysztof Kozlowski and committed by
Mark Brown
6b99dc62 7817eb1a

+201
+201
sound/soc/codecs/wsa884x.c
··· 5 5 */ 6 6 7 7 #include <linux/bitfield.h> 8 + #include <linux/cleanup.h> 8 9 #include <linux/device.h> 9 10 #include <linux/gpio/consumer.h> 11 + #include <linux/hwmon.h> 10 12 #include <linux/init.h> 11 13 #include <linux/kernel.h> 12 14 #include <linux/module.h> 15 + #include <linux/mutex.h> 13 16 #include <linux/pm_runtime.h> 14 17 #include <linux/regmap.h> 15 18 #include <linux/regulator/consumer.h> ··· 304 301 #define WSA884X_PA_FSM_MSK1 (WSA884X_DIG_CTRL0_BASE + 0x3b) 305 302 #define WSA884X_PA_FSM_BYP_CTL (WSA884X_DIG_CTRL0_BASE + 0x3c) 306 303 #define WSA884X_PA_FSM_BYP0 (WSA884X_DIG_CTRL0_BASE + 0x3d) 304 + #define WSA884X_PA_FSM_BYP0_DC_CAL_EN_MASK 0x01 305 + #define WSA884X_PA_FSM_BYP0_DC_CAL_EN_SHIFT 0 306 + #define WSA884X_PA_FSM_BYP0_CLK_WD_EN_MASK 0x02 307 + #define WSA884X_PA_FSM_BYP0_CLK_WD_EN_SHIFT 1 308 + #define WSA884X_PA_FSM_BYP0_BG_EN_MASK 0x04 309 + #define WSA884X_PA_FSM_BYP0_BG_EN_SHIFT 2 310 + #define WSA884X_PA_FSM_BYP0_BOOST_EN_MASK 0x08 311 + #define WSA884X_PA_FSM_BYP0_BOOST_EN_SHIFT 3 312 + #define WSA884X_PA_FSM_BYP0_PA_EN_MASK 0x10 313 + #define WSA884X_PA_FSM_BYP0_PA_EN_SHIFT 4 314 + #define WSA884X_PA_FSM_BYP0_D_UNMUTE_MASK 0x20 315 + #define WSA884X_PA_FSM_BYP0_D_UNMUTE_SHIFT 5 316 + #define WSA884X_PA_FSM_BYP0_SPKR_PROT_EN_MASK 0x40 317 + #define WSA884X_PA_FSM_BYP0_SPKR_PROT_EN_SHIFT 6 318 + #define WSA884X_PA_FSM_BYP0_TSADC_EN_MASK 0x80 319 + #define WSA884X_PA_FSM_BYP0_TSADC_EN_SHIFT 7 307 320 #define WSA884X_PA_FSM_BYP1 (WSA884X_DIG_CTRL0_BASE + 0x3e) 308 321 #define WSA884X_TADC_VALUE_CTL (WSA884X_DIG_CTRL0_BASE + 0x50) 322 + #define WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK 0x01 323 + #define WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_SHIFT 0 324 + #define WSA884X_TADC_VALUE_CTL_VBAT_VALUE_RD_EN_MASK 0x02 325 + #define WSA884X_TADC_VALUE_CTL_VBAT_VALUE_RD_EN_SHIFT 1 309 326 #define WSA884X_TEMP_DETECT_CTL (WSA884X_DIG_CTRL0_BASE + 0x51) 310 327 #define WSA884X_TEMP_DIN_MSB (WSA884X_DIG_CTRL0_BASE + 0x52) 311 328 #define WSA884X_TEMP_DIN_LSB (WSA884X_DIG_CTRL0_BASE + 0x53) ··· 714 691 SNDRV_PCM_FMTBIT_S24_LE |\ 715 692 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) 716 693 694 + /* Two-point trimming for temperature calibration */ 695 + #define WSA884X_T1_TEMP -10L 696 + #define WSA884X_T2_TEMP 150L 697 + 698 + /* 699 + * Device will report senseless data in many cases, so discard any measurements 700 + * outside of valid range. 701 + */ 702 + #define WSA884X_LOW_TEMP_THRESHOLD 5 703 + #define WSA884X_HIGH_TEMP_THRESHOLD 45 704 + 717 705 struct wsa884x_priv { 718 706 struct regmap *regmap; 719 707 struct device *dev; ··· 740 706 int active_ports; 741 707 int dev_mode; 742 708 bool hw_init; 709 + /* 710 + * Protects temperature reading code (related to speaker protection) and 711 + * fields: temperature and pa_on. 712 + */ 713 + struct mutex sp_lock; 714 + unsigned int temperature; 715 + bool pa_on; 743 716 }; 744 717 745 718 enum { ··· 1701 1660 1702 1661 switch (event) { 1703 1662 case SND_SOC_DAPM_POST_PMU: 1663 + mutex_lock(&wsa884x->sp_lock); 1664 + wsa884x->pa_on = true; 1665 + mutex_unlock(&wsa884x->sp_lock); 1666 + 1704 1667 wsa884x_spkr_post_pmu(component, wsa884x); 1705 1668 1706 1669 snd_soc_component_write_field(component, WSA884X_PDM_WD_CTL, ··· 1716 1671 snd_soc_component_write_field(component, WSA884X_PDM_WD_CTL, 1717 1672 WSA884X_PDM_WD_CTL_PDM_WD_EN_MASK, 1718 1673 0x0); 1674 + 1675 + mutex_lock(&wsa884x->sp_lock); 1676 + wsa884x->pa_on = false; 1677 + mutex_unlock(&wsa884x->sp_lock); 1719 1678 break; 1720 1679 } 1721 1680 ··· 1859 1810 }, 1860 1811 }; 1861 1812 1813 + static int wsa884x_get_temp(struct wsa884x_priv *wsa884x, long *temp) 1814 + { 1815 + unsigned int d1_msb = 0, d1_lsb = 0, d2_msb = 0, d2_lsb = 0; 1816 + unsigned int dmeas_msb = 0, dmeas_lsb = 0; 1817 + int d1, d2, dmeas; 1818 + unsigned int mask; 1819 + long val; 1820 + int ret; 1821 + 1822 + guard(mutex)(&wsa884x->sp_lock); 1823 + 1824 + if (wsa884x->pa_on) { 1825 + /* 1826 + * Reading temperature is possible only when Power Amplifier is 1827 + * off. Report last cached data. 1828 + */ 1829 + *temp = wsa884x->temperature; 1830 + return 0; 1831 + } 1832 + 1833 + ret = pm_runtime_resume_and_get(wsa884x->dev); 1834 + if (ret < 0) 1835 + return ret; 1836 + 1837 + mask = WSA884X_PA_FSM_BYP0_DC_CAL_EN_MASK | 1838 + WSA884X_PA_FSM_BYP0_CLK_WD_EN_MASK | 1839 + WSA884X_PA_FSM_BYP0_BG_EN_MASK | 1840 + WSA884X_PA_FSM_BYP0_D_UNMUTE_MASK | 1841 + WSA884X_PA_FSM_BYP0_SPKR_PROT_EN_MASK | 1842 + WSA884X_PA_FSM_BYP0_TSADC_EN_MASK; 1843 + /* 1844 + * Here and further do not care about read or update failures. 1845 + * For example, before turning on Power Amplifier for the first 1846 + * time, reading WSA884X_TEMP_DIN_MSB will always return 0. 1847 + * Instead, check if returned value is within reasonable 1848 + * thresholds. 1849 + */ 1850 + regmap_update_bits(wsa884x->regmap, WSA884X_PA_FSM_BYP0, mask, mask); 1851 + 1852 + regmap_update_bits(wsa884x->regmap, WSA884X_TADC_VALUE_CTL, 1853 + WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK, 1854 + FIELD_PREP(WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK, 0x0)); 1855 + 1856 + regmap_read(wsa884x->regmap, WSA884X_TEMP_DIN_MSB, &dmeas_msb); 1857 + regmap_read(wsa884x->regmap, WSA884X_TEMP_DIN_LSB, &dmeas_lsb); 1858 + 1859 + regmap_update_bits(wsa884x->regmap, WSA884X_TADC_VALUE_CTL, 1860 + WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK, 1861 + FIELD_PREP(WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK, 0x1)); 1862 + 1863 + regmap_read(wsa884x->regmap, WSA884X_OTP_REG_1, &d1_msb); 1864 + regmap_read(wsa884x->regmap, WSA884X_OTP_REG_2, &d1_lsb); 1865 + regmap_read(wsa884x->regmap, WSA884X_OTP_REG_3, &d2_msb); 1866 + regmap_read(wsa884x->regmap, WSA884X_OTP_REG_4, &d2_lsb); 1867 + 1868 + regmap_update_bits(wsa884x->regmap, WSA884X_PA_FSM_BYP0, mask, 0x0); 1869 + 1870 + dmeas = (((dmeas_msb & 0xff) << 0x8) | (dmeas_lsb & 0xff)) >> 0x6; 1871 + d1 = (((d1_msb & 0xff) << 0x8) | (d1_lsb & 0xff)) >> 0x6; 1872 + d2 = (((d2_msb & 0xff) << 0x8) | (d2_lsb & 0xff)) >> 0x6; 1873 + 1874 + if (d1 == d2) { 1875 + /* Incorrect data in OTP? */ 1876 + ret = -EINVAL; 1877 + goto out; 1878 + } 1879 + 1880 + val = WSA884X_T1_TEMP + (((dmeas - d1) * (WSA884X_T2_TEMP - WSA884X_T1_TEMP))/(d2 - d1)); 1881 + 1882 + dev_dbg(wsa884x->dev, "Measured temp %ld (dmeas=%d, d1=%d, d2=%d)\n", 1883 + val, dmeas, d1, d2); 1884 + 1885 + if ((val > WSA884X_LOW_TEMP_THRESHOLD) && 1886 + (val < WSA884X_HIGH_TEMP_THRESHOLD)) { 1887 + wsa884x->temperature = val; 1888 + *temp = val; 1889 + ret = 0; 1890 + } else { 1891 + ret = -EAGAIN; 1892 + } 1893 + 1894 + out: 1895 + pm_runtime_mark_last_busy(wsa884x->dev); 1896 + pm_runtime_put_autosuspend(wsa884x->dev); 1897 + 1898 + return ret; 1899 + } 1900 + 1901 + static umode_t wsa884x_hwmon_is_visible(const void *data, 1902 + enum hwmon_sensor_types type, u32 attr, 1903 + int channel) 1904 + { 1905 + if (type != hwmon_temp) 1906 + return 0; 1907 + 1908 + switch (attr) { 1909 + case hwmon_temp_input: 1910 + return 0444; 1911 + default: 1912 + break; 1913 + } 1914 + 1915 + return 0; 1916 + } 1917 + 1918 + static int wsa884x_hwmon_read(struct device *dev, 1919 + enum hwmon_sensor_types type, 1920 + u32 attr, int channel, long *temp) 1921 + { 1922 + int ret; 1923 + 1924 + switch (attr) { 1925 + case hwmon_temp_input: 1926 + ret = wsa884x_get_temp(dev_get_drvdata(dev), temp); 1927 + break; 1928 + default: 1929 + ret = -EOPNOTSUPP; 1930 + break; 1931 + } 1932 + 1933 + return ret; 1934 + } 1935 + 1936 + static const struct hwmon_channel_info *const wsa884x_hwmon_info[] = { 1937 + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), 1938 + NULL 1939 + }; 1940 + 1941 + static const struct hwmon_ops wsa884x_hwmon_ops = { 1942 + .is_visible = wsa884x_hwmon_is_visible, 1943 + .read = wsa884x_hwmon_read, 1944 + }; 1945 + 1946 + static const struct hwmon_chip_info wsa884x_hwmon_chip_info = { 1947 + .ops = &wsa884x_hwmon_ops, 1948 + .info = wsa884x_hwmon_info, 1949 + }; 1950 + 1862 1951 static void wsa884x_reset_powerdown(void *data) 1863 1952 { 1864 1953 struct wsa884x_priv *wsa884x = data; ··· 2052 1865 wsa884x = devm_kzalloc(dev, sizeof(*wsa884x), GFP_KERNEL); 2053 1866 if (!wsa884x) 2054 1867 return -ENOMEM; 1868 + 1869 + mutex_init(&wsa884x->sp_lock); 2055 1870 2056 1871 for (i = 0; i < WSA884X_SUPPLIES_NUM; i++) 2057 1872 wsa884x->supplies[i].supply = wsa884x_supply_name[i]; ··· 2111 1922 /* Start in cache-only until device is enumerated */ 2112 1923 regcache_cache_only(wsa884x->regmap, true); 2113 1924 wsa884x->hw_init = true; 1925 + 1926 + if (IS_REACHABLE(CONFIG_HWMON)) { 1927 + struct device *hwmon; 1928 + 1929 + hwmon = devm_hwmon_device_register_with_info(dev, "wsa884x", 1930 + wsa884x, 1931 + &wsa884x_hwmon_chip_info, 1932 + NULL); 1933 + if (IS_ERR(hwmon)) 1934 + return dev_err_probe(dev, PTR_ERR(hwmon), 1935 + "Failed to register hwmon sensor\n"); 1936 + } 2114 1937 2115 1938 pm_runtime_set_autosuspend_delay(dev, 3000); 2116 1939 pm_runtime_use_autosuspend(dev);