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

thermal: broadcom: add Northstar thermal driver

Northstar is a SoC family commonly used in home routers. This commit
adds a driver for checking CPU temperature. As Northstar Plus seems to
also have this IP block this new symbol gets ARCH_BCM_IPROC dependency.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
Signed-off-by: Eduardo Valentin <edubezval@gmail.com>

authored by

Rafał Miłecki and committed by
Eduardo Valentin
a94cb7ee ee7cdbec

+120
+5
drivers/thermal/Kconfig
··· 392 392 Enable this option if you want to have support for thermal management 393 393 controller present in Mediatek SoCs 394 394 395 + menu "Broadcom thermal drivers" 396 + depends on ARCH_BCM || COMPILE_TEST 397 + source "drivers/thermal/broadcom/Kconfig" 398 + endmenu 399 + 395 400 menu "Texas Instruments thermal drivers" 396 401 depends on ARCH_HAS_BANDGAP || COMPILE_TEST 397 402 depends on HAS_IOMEM
+1
drivers/thermal/Makefile
··· 27 27 thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o 28 28 29 29 # platform thermal drivers 30 + obj-y += broadcom/ 30 31 obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o 31 32 obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o 32 33 obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o
+8
drivers/thermal/broadcom/Kconfig
··· 1 + config BCM_NS_THERMAL 2 + tristate "Northstar thermal driver" 3 + depends on ARCH_BCM_IPROC || COMPILE_TEST 4 + help 5 + Northstar is a family of SoCs that includes e.g. BCM4708, BCM47081, 6 + BCM4709 and BCM47094. It contains DMU (Device Management Unit) block 7 + with a thermal sensor that allows checking CPU temperature. This 8 + driver provides support for it.
+1
drivers/thermal/broadcom/Makefile
··· 1 + obj-$(CONFIG_BCM_NS_THERMAL) += ns-thermal.o
+105
drivers/thermal/broadcom/ns-thermal.c
··· 1 + /* 2 + * Copyright (C) 2017 Rafał Miłecki <rafal@milecki.pl> 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #include <linux/module.h> 10 + #include <linux/of_address.h> 11 + #include <linux/platform_device.h> 12 + #include <linux/thermal.h> 13 + 14 + #define PVTMON_CONTROL0 0x00 15 + #define PVTMON_CONTROL0_SEL_MASK 0x0000000e 16 + #define PVTMON_CONTROL0_SEL_TEMP_MONITOR 0x00000000 17 + #define PVTMON_CONTROL0_SEL_TEST_MODE 0x0000000e 18 + #define PVTMON_STATUS 0x08 19 + 20 + struct ns_thermal { 21 + struct thermal_zone_device *tz; 22 + void __iomem *pvtmon; 23 + }; 24 + 25 + static int ns_thermal_get_temp(void *data, int *temp) 26 + { 27 + struct ns_thermal *ns_thermal = data; 28 + int offset = thermal_zone_get_offset(ns_thermal->tz); 29 + int slope = thermal_zone_get_slope(ns_thermal->tz); 30 + u32 val; 31 + 32 + val = readl(ns_thermal->pvtmon + PVTMON_CONTROL0); 33 + if ((val & PVTMON_CONTROL0_SEL_MASK) != PVTMON_CONTROL0_SEL_TEMP_MONITOR) { 34 + /* Clear current mode selection */ 35 + val &= ~PVTMON_CONTROL0_SEL_MASK; 36 + 37 + /* Set temp monitor mode (it's the default actually) */ 38 + val |= PVTMON_CONTROL0_SEL_TEMP_MONITOR; 39 + 40 + writel(val, ns_thermal->pvtmon + PVTMON_CONTROL0); 41 + } 42 + 43 + val = readl(ns_thermal->pvtmon + PVTMON_STATUS); 44 + *temp = slope * val + offset; 45 + 46 + return 0; 47 + } 48 + 49 + static const struct thermal_zone_of_device_ops ns_thermal_ops = { 50 + .get_temp = ns_thermal_get_temp, 51 + }; 52 + 53 + static int ns_thermal_probe(struct platform_device *pdev) 54 + { 55 + struct device *dev = &pdev->dev; 56 + struct ns_thermal *ns_thermal; 57 + 58 + ns_thermal = devm_kzalloc(dev, sizeof(*ns_thermal), GFP_KERNEL); 59 + if (!ns_thermal) 60 + return -ENOMEM; 61 + 62 + ns_thermal->pvtmon = of_iomap(dev_of_node(dev), 0); 63 + if (WARN_ON(!ns_thermal->pvtmon)) 64 + return -ENOENT; 65 + 66 + ns_thermal->tz = devm_thermal_zone_of_sensor_register(dev, 0, 67 + ns_thermal, 68 + &ns_thermal_ops); 69 + if (IS_ERR(ns_thermal->tz)) { 70 + iounmap(ns_thermal->pvtmon); 71 + return PTR_ERR(ns_thermal->tz); 72 + } 73 + 74 + platform_set_drvdata(pdev, ns_thermal); 75 + 76 + return 0; 77 + } 78 + 79 + static int ns_thermal_remove(struct platform_device *pdev) 80 + { 81 + struct ns_thermal *ns_thermal = platform_get_drvdata(pdev); 82 + 83 + iounmap(ns_thermal->pvtmon); 84 + 85 + return 0; 86 + } 87 + 88 + static const struct of_device_id ns_thermal_of_match[] = { 89 + { .compatible = "brcm,ns-thermal", }, 90 + {}, 91 + }; 92 + MODULE_DEVICE_TABLE(of, ns_thermal_of_match); 93 + 94 + static struct platform_driver ns_thermal_driver = { 95 + .probe = ns_thermal_probe, 96 + .remove = ns_thermal_remove, 97 + .driver = { 98 + .name = "ns-thermal", 99 + .of_match_table = ns_thermal_of_match, 100 + }, 101 + }; 102 + module_platform_driver(ns_thermal_driver); 103 + 104 + MODULE_DESCRIPTION("Northstar thermal driver"); 105 + MODULE_LICENSE("GPL v2");