From d1066d775e67c33cc93178475c4485c5ef0a83c9 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 18 May 2019 12:26:11 +0200 Subject: [PATCH] thermal: brcmstb_thermal: Add BCM2838 support The BCM2838 has an AVS TMON hardware block. This adds the necessary support to the brcmstb_thermal driver ( no trip handling ). Signed-off-by: Stefan Wahren --- drivers/thermal/broadcom/Kconfig | 2 +- drivers/thermal/broadcom/brcmstb_thermal.c | 61 +++++++++++++++++++--- 2 files changed, 54 insertions(+), 9 deletions(-) --- a/drivers/thermal/broadcom/Kconfig +++ b/drivers/thermal/broadcom/Kconfig @@ -9,7 +9,7 @@ config BCM2835_THERMAL config BRCMSTB_THERMAL tristate "Broadcom STB AVS TMON thermal driver" - depends on ARCH_BRCMSTB || COMPILE_TEST + depends on ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST help Enable this driver if you have a Broadcom STB SoC and would like thermal framework support. --- a/drivers/thermal/broadcom/brcmstb_thermal.c +++ b/drivers/thermal/broadcom/brcmstb_thermal.c @@ -10,6 +10,7 @@ #define pr_fmt(fmt) DRV_NAME ": " fmt #include +#include #include #include #include @@ -22,9 +23,6 @@ #include #define AVS_TMON_STATUS 0x00 - #define AVS_TMON_STATUS_valid_msk BIT(11) - #define AVS_TMON_STATUS_data_msk GENMASK(10, 1) - #define AVS_TMON_STATUS_data_shift 1 #define AVS_TMON_EN_OVERTEMP_RESET 0x04 #define AVS_TMON_EN_OVERTEMP_RESET_msk BIT(0) @@ -102,10 +100,19 @@ static struct avs_tmon_trip avs_tmon_tri }, }; +struct brcmstb_thermal_of_data { + const struct thermal_zone_of_device_ops *of_ops; + u32 status_valid_mask; + u32 status_data_mask; + u32 status_data_shift; +}; + struct brcmstb_thermal_priv { void __iomem *tmon_base; struct device *dev; struct thermal_zone_device *thermal; + struct clk *clk; + const struct brcmstb_thermal_of_data *socdata; }; /* Convert a HW code to a temperature reading (millidegree celsius) */ @@ -142,17 +149,18 @@ static inline u32 avs_tmon_temp_to_code( static int brcmstb_get_temp(void *data, int *temp) { struct brcmstb_thermal_priv *priv = data; + const struct brcmstb_thermal_of_data *socdata = priv->socdata; u32 val; long t; val = __raw_readl(priv->tmon_base + AVS_TMON_STATUS); - if (!(val & AVS_TMON_STATUS_valid_msk)) { + if (!(val & socdata->status_valid_mask)) { dev_err(priv->dev, "reading not valid\n"); return -EIO; } - val = (val & AVS_TMON_STATUS_data_msk) >> AVS_TMON_STATUS_data_shift; + val = (val & socdata->status_data_mask) >> socdata->status_data_shift; t = avs_tmon_code_to_temp(priv->thermal, val); if (t < 0) @@ -277,13 +285,34 @@ static int brcmstb_set_trips(void *data, return 0; } -static const struct thermal_zone_of_device_ops of_ops = { +static const struct thermal_zone_of_device_ops bcm7445_thermal_of_ops = { .get_temp = brcmstb_get_temp, .set_trips = brcmstb_set_trips, }; +static const struct thermal_zone_of_device_ops bcm2838_thermal_of_ops = { + .get_temp = brcmstb_get_temp, +}; + +static const struct brcmstb_thermal_of_data bcm7445_thermal_of_data = { + .of_ops = &bcm7445_thermal_of_ops, + .status_valid_mask = BIT(11), + .status_data_mask = GENMASK(10, 1), + .status_data_shift = 1, +}; + +static const struct brcmstb_thermal_of_data bcm2838_thermal_of_data = { + .of_ops = &bcm2838_thermal_of_ops, + .status_valid_mask = BIT(10), + .status_data_mask = GENMASK(9, 0), + .status_data_shift = 0, +}; + static const struct of_device_id brcmstb_thermal_id_table[] = { - { .compatible = "brcm,avs-tmon" }, + { .compatible = "brcm,avs-tmon", + .data = &bcm7445_thermal_of_data }, + { .compatible = "brcm,avs-tmon-bcm2838", + .data = &bcm2838_thermal_of_data }, {}, }; MODULE_DEVICE_TABLE(of, brcmstb_thermal_id_table); @@ -304,11 +333,27 @@ static int brcmstb_thermal_probe(struct if (IS_ERR(priv->tmon_base)) return PTR_ERR(priv->tmon_base); + priv->socdata = of_device_get_match_data(&pdev->dev); + if (!priv->socdata) { + dev_err(&pdev->dev, "no device match found\n"); + return -ENODEV; + } + + priv->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(priv->clk) && PTR_ERR(priv->clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + if (!IS_ERR(priv->clk)) { + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + } + priv->dev = &pdev->dev; platform_set_drvdata(pdev, priv); thermal = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, priv, - &of_ops); + priv->socdata->of_ops); if (IS_ERR(thermal)) { ret = PTR_ERR(thermal); dev_err(&pdev->dev, "could not register sensor: %d\n", ret);