thermal: add thermal driver support for m8b
authorTao Zeng <tao.zeng@amlogic.com>
Fri, 14 Apr 2017 07:19:43 +0000 (15:19 +0800)
committerJianxin Pan <jianxin.pan@amlogic.com>
Fri, 14 Apr 2017 10:47:16 +0000 (18:47 +0800)
PD#141217: proting thermal drivers for m8b

1. add dts and config for m8b;
2. add driver files for m8b

Change-Id: Ice060dab0513a6b18122c7abd319915057cac4ac
Signed-off-by: Tao Zeng <tao.zeng@amlogic.com>
arch/arm/boot/dts/amlogic/meson8b_m200.dts
arch/arm/boot/dts/amlogic/meson8b_m400.dts
arch/arm/configs/meson32_defconfig
drivers/amlogic/thermal/Kconfig
drivers/amlogic/thermal/Makefile
drivers/amlogic/thermal/aml_thermal_hw_m8b.c [new file with mode: 0644]
drivers/amlogic/thermal/cpucore_cooling.c
include/linux/amlogic/aml_thermal_hw.h

index 353ff97..8e33fec 100644 (file)
                pinctrl-0=<&hdmi_cec_1>;
                reg = <0xc8100000 0x200>;
        };
+
+       aml_sensor0: aml-sensor@0 {
+               compatible = "amlogic, aml-thermal";
+               device_name = "thermal";
+               #thermal-sensor-cells = <1>;
+               cooling_devices {
+                       cpufreq_cool_cluster0 {
+                               min_state = <768000>;
+                               dyn_coeff = <110>;
+                               cluster_id = <0>;
+                               node_name = "cpufreq_cool0";
+                               device_type = "cpufreq";
+                       };
+                       cpucore_cool_cluster0 {
+                               min_state = <1>;
+                               dyn_coeff = <0>;
+                               cluster_id = <0>;
+                               node_name = "cpucore_cool0";
+                               device_type = "cpucore";
+                       };
+                       gpufreq_cool {
+                               min_state = <318>;
+                               dyn_coeff = <437>;
+                               cluster_id = <0>;
+                               node_name = "gpufreq_cool0";
+                               device_type = "gpufreq";
+                       };
+                       gpucore_cool {
+                               min_state = <1>;
+                               dyn_coeff = <0>;
+                               cluster_id = <0>;
+                               node_name = "gpucore_cool0";
+                               device_type = "gpucore";
+                       };
+               };
+               cpufreq_cool0:cpufreq_cool0 {
+                       #cooling-cells = <2>; /* min followed by max */
+               };
+               cpucore_cool0:cpucore_cool0 {
+                       #cooling-cells = <2>; /* min followed by max */
+               };
+               gpufreq_cool0:gpufreq_cool0 {
+                       #cooling-cells = <2>; /* min followed by max */
+               };
+               gpucore_cool0:gpucore_cool0 {
+                       #cooling-cells = <2>; /* min followed by max */
+               };
+       };
+       thermal-zones {
+               soc_thermal {
+                       polling-delay = <1000>;
+                       polling-delay-passive = <100>;
+                       sustainable-power = <1350>;
+
+                       thermal-sensors = <&aml_sensor0 3>;
+
+                       trips {
+                               switch_on: trip-point@0 {
+                                       temperature = <70000>;
+                                       hysteresis = <1000>;
+                                       type = "passive";
+                               };
+                               control: trip-point@1 {
+                                       temperature = <80000>;
+                                       hysteresis = <1000>;
+                                       type = "passive";
+                               };
+                               hot: trip-point@2 {
+                                       temperature = <85000>;
+                                       hysteresis = <5000>;
+                                       type = "hot";
+                               };
+                               critical: trip-point@3 {
+                                       temperature = <260000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               cpufreq_cooling_map {
+                                       trip = <&control>;
+                                       cooling-device = <&cpufreq_cool0 0 4>;
+                                       contribution = <1024>;
+                               };
+                               cpucore_cooling_map {
+                                       trip = <&control>;
+                                       cooling-device = <&cpucore_cool0 0 3>;
+                                       contribution = <1024>;
+                               };
+                               gpufreq_cooling_map {
+                                       trip = <&control>;
+                                       cooling-device = <&gpufreq_cool0 0 4>;
+                                       contribution = <1024>;
+                               };
+                               gpucore_cooling_map {
+                                       trip = <&control>;
+                                       cooling-device = <&gpucore_cool0 0 2>;
+                                       contribution = <1024>;
+                               };
+                       };
+               };
+       };
 };
 
 &uart_AO {
index fbdfea9..68860f7 100644 (file)
                         */
                };
        };
+       cpufreq-meson{
+               compatible = "amlogic, cpufreq-meson";
+               status = "okay";
+               fixpll_target = <1536000>;
+               clocks = <&clkc CLKID_CPUCLK>,
+                        <&clkc CLKID_PLL_SYS>;
+               clock-names = "cpu_clk", "sys_clk";
+               opp_table = <
+                       /* frequent(Khz)    uV    */
+                                 96000  860000
+                                312000  860000
+                                504000  860000
+                                600000  860000
+                                720000  860000
+                                816000  900000
+                               1008000 1140000
+                               1200000 1140000
+                               1320000 1140000
+                               1488000 1140000
+                               1536000 1140000
+                       >;
+       };
+
+       dvfs {
+               compatible = "amlogic, amlogic-dvfs";
+               status = "okay";
+               vcck_dvfs {
+                       dvfs_id = <1>;
+               };
+       };
+
+       pmu {
+               compatible = "amlogic, aml_pmu_prober";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "okay";
+               aml1218 {
+                       compatible = "amlogic, amlogic_pmu";
+                       sub_type = "aml1218_pmu";
+                       i2c_bus = "i2c_bus_ao";
+                       slave_address = <0x35>;
+                       status = "okay";
+               };
+       };
+
+       aocec: aocec{
+               compatible = "amlogic, amlogic-aocec";
+               device_name = "aocec";
+               status = "okay";
+               vendor_id = <0x000000>;
+               cec_osd_string = "MBox"; /* Max Chars: 14    */
+               cec_version = <6>; /* 5: 1.4, 6: 2.0 */
+               port_num = <1>;
+               arc_port_mask = <0x0>;
+               interrupts = <0 151 1>;
+               interrupt-names = "hdmi_aocec";
+               pinctrl-names = "hdmi_cec_1";
+               pinctrl-0=<&hdmi_cec_1>;
+               reg = <0xc8100000 0x200>;
+       };
+
+       aml_sensor0: aml-sensor@0 {
+               compatible = "amlogic, aml-thermal";
+               device_name = "thermal";
+               #thermal-sensor-cells = <1>;
+               cooling_devices {
+                       cpufreq_cool_cluster0 {
+                               min_state = <768000>;
+                               dyn_coeff = <110>;
+                               cluster_id = <0>;
+                               node_name = "cpufreq_cool0";
+                               device_type = "cpufreq";
+                       };
+                       cpucore_cool_cluster0 {
+                               min_state = <1>;
+                               dyn_coeff = <0>;
+                               cluster_id = <0>;
+                               node_name = "cpucore_cool0";
+                               device_type = "cpucore";
+                       };
+                       gpufreq_cool {
+                               min_state = <318>;
+                               dyn_coeff = <437>;
+                               cluster_id = <0>;
+                               node_name = "gpufreq_cool0";
+                               device_type = "gpufreq";
+                       };
+                       gpucore_cool {
+                               min_state = <1>;
+                               dyn_coeff = <0>;
+                               cluster_id = <0>;
+                               node_name = "gpucore_cool0";
+                               device_type = "gpucore";
+                       };
+               };
+               cpufreq_cool0:cpufreq_cool0 {
+                       #cooling-cells = <2>; /* min followed by max */
+               };
+               cpucore_cool0:cpucore_cool0 {
+                       #cooling-cells = <2>; /* min followed by max */
+               };
+               gpufreq_cool0:gpufreq_cool0 {
+                       #cooling-cells = <2>; /* min followed by max */
+               };
+               gpucore_cool0:gpucore_cool0 {
+                       #cooling-cells = <2>; /* min followed by max */
+               };
+       };
+       thermal-zones {
+               soc_thermal {
+                       polling-delay = <1000>;
+                       polling-delay-passive = <100>;
+                       sustainable-power = <1350>;
+
+                       thermal-sensors = <&aml_sensor0 3>;
+
+                       trips {
+                               switch_on: trip-point@0 {
+                                       temperature = <70000>;
+                                       hysteresis = <1000>;
+                                       type = "passive";
+                               };
+                               control: trip-point@1 {
+                                       temperature = <80000>;
+                                       hysteresis = <1000>;
+                                       type = "passive";
+                               };
+                               hot: trip-point@2 {
+                                       temperature = <85000>;
+                                       hysteresis = <5000>;
+                                       type = "hot";
+                               };
+                               critical: trip-point@3 {
+                                       temperature = <260000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               cpufreq_cooling_map {
+                                       trip = <&control>;
+                                       cooling-device = <&cpufreq_cool0 0 4>;
+                                       contribution = <1024>;
+                               };
+                               cpucore_cooling_map {
+                                       trip = <&control>;
+                                       cooling-device = <&cpucore_cool0 0 3>;
+                                       contribution = <1024>;
+                               };
+                               gpufreq_cooling_map {
+                                       trip = <&control>;
+                                       cooling-device = <&gpufreq_cool0 0 4>;
+                                       contribution = <1024>;
+                               };
+                               gpucore_cooling_map {
+                                       trip = <&control>;
+                                       cooling-device = <&gpucore_cool0 0 2>;
+                                       contribution = <1024>;
+                               };
+                       };
+               };
+       };
 };
 
 &uart_AO {
index f92b68d..4b4bd88 100644 (file)
@@ -60,15 +60,20 @@ CONFIG_AMLOGIC_CLK=y
 CONFIG_AMLOGIC_M8B_CLK=y
 CONFIG_AMLOGIC_CRYPTO=y
 CONFIG_AMLOGIC_CRYPTO_BLKMV=y
+CONFIG_AMLOGIC_INPUT=y
+CONFIG_AMLOGIC_SARADC=y
 CONFIG_AMLOGIC_EFUSE=y
 CONFIG_AMLOGIC_CPU_HOTPLUG=y
 CONFIG_AMLOGIC_PWM=y
-CONFIG_AMLOGIC_INPUT=y
-CONFIG_AMLOGIC_SARADC=y
 CONFIG_AMLOGIC_MMC=y
 CONFIG_AMLOGIC_M8B_MMC=y
 CONFIG_AMLOGIC_CEC=y
 CONFIG_AMLOGIC_M8B_CEC=y
+CONFIG_AMLOGIC_TEMP_SENSOR=y
+CONFIG_AMLOGIC_M8B_TEMP_SENSOR=y
+CONFIG_AMLOGIC_CPUCORE_THERMAL=y
+CONFIG_AMLOGIC_GPU_THERMAL=y
+CONFIG_AMLOGIC_GPUCORE_THERMAL=y
 CONFIG_AMLOGIC_POWER=y
 CONFIG_AMLOGIC_PMU_OF=y
 CONFIG_AMLOGIC_PMU=y
@@ -100,6 +105,11 @@ CONFIG_POWER_RESET_GPIO=y
 CONFIG_POWER_RESET_GPIO_RESTART=y
 CONFIG_POWER_RESET_SYSCON=y
 CONFIG_POWER_SUPPLY=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_WRITABLE_TRIPS=y
+CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_CPU_THERMAL=y
 CONFIG_WATCHDOG=y
 CONFIG_WATCHDOG_CORE=y
 CONFIG_BCMA=y
index 861cf17..b5305f0 100644 (file)
@@ -6,6 +6,7 @@ menu "Amlogic temperature sensor"
 
 config AMLOGIC_TEMP_SENSOR
        bool "Amlgoic temperature sensor Support"
+       depends on THERMAL
        default n
        ---help---
                Thermal sensor low level support for thermal
@@ -14,6 +15,24 @@ config AMLOGIC_TEMP_SENSOR
 
                If you wan this driver, selest it.
 
+config AMLOGIC_M8B_TEMP_SENSOR
+       bool "Amlgoic temperature sensor Support for M8 chips"
+       depends on AMLOGIC_TEMP_SENSOR
+       depends on MACH_MESON8B
+       default n
+       help
+               this config enables thermal driver for M8/M8baby chips.
+               Say Y if you want this driver.
+
+config AMLOGIC_GX_TEMP_SENSOR
+       bool "Amlgoic temperature sensor Support for GX chips"
+       depends on AMLOGIC_TEMP_SENSOR
+       depends on ARM64
+       default y
+       help
+               this config enables thermal driver for GX/GXB/GXL/GXM chips.
+               Say Y if you want this driver.
+
 config AMLOGIC_CPUCORE_THERMAL
        bool "generic cpu core cooling support"
        depends on AMLOGIC_TEMP_SENSOR
index 79cd77a..1599773 100644 (file)
@@ -1,5 +1,6 @@
 
-obj-$(CONFIG_AMLOGIC_TEMP_SENSOR)      += aml_thermal_hw.o
+obj-$(CONFIG_AMLOGIC_GX_TEMP_SENSOR)   += aml_thermal_hw.o
+obj-$(CONFIG_AMLOGIC_M8B_TEMP_SENSOR)  += aml_thermal_hw_m8b.o
 obj-$(CONFIG_AMLOGIC_CPUCORE_THERMAL)  += cpucore_cooling.o
 obj-$(CONFIG_AMLOGIC_GPU_THERMAL)      += gpu_cooling.o
 obj-$(CONFIG_AMLOGIC_GPUCORE_THERMAL)  += gpucore_cooling.o
diff --git a/drivers/amlogic/thermal/aml_thermal_hw_m8b.c b/drivers/amlogic/thermal/aml_thermal_hw_m8b.c
new file mode 100644 (file)
index 0000000..cb2cced
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * drivers/amlogic/thermal/aml_thermal_hw_m8b.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/amlogic/cpu_version.h>
+#include <linux/amlogic/scpi_protocol.h>
+#include <linux/printk.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/cpufreq.h>
+#include <linux/cpu_cooling.h>
+#include <linux/amlogic/cpucore_cooling.h>
+#include <linux/amlogic/gpucore_cooling.h>
+#include <linux/amlogic/gpu_cooling.h>
+#include <linux/amlogic/saradc.h>
+#include <linux/amlogic/efuse.h>
+#include <linux/cpu.h>
+#include <linux/amlogic/aml_thermal_hw.h>
+
+#define NOT_WRITE_EFUSE                0x0
+#define EFUEE_PRIVATE          0x4
+#define EFUSE_OPS              0xa
+
+#define TEMP_ADC_CHANNEL       6
+#define TEMP_NOT_TRIMMED       (-1000)
+#define TEMP_ADC_ERROR         (-1001)
+
+enum cluster_type {
+       CLUSTER_BIG = 0,
+       CLUSTER_LITTLE,
+       NUM_CLUSTERS
+};
+
+enum cool_dev_type {
+       COOL_DEV_TYPE_CPU_FREQ = 0,
+       COOL_DEV_TYPE_CPU_CORE,
+       COOL_DEV_TYPE_GPU_FREQ,
+       COOL_DEV_TYPE_GPU_CORE,
+       COOL_DEV_TYPE_MAX
+};
+
+struct cool_dev {
+       int min_state;
+       int coeff;
+       int cluster_id;
+       char *device_type;
+       struct device_node *np;
+       struct thermal_cooling_device *cooling_dev;
+};
+
+struct aml_thermal_sensor {
+       bool chip_trimmed          : 1;
+       bool adc_flag              : 1;
+       unsigned int fix_value     : 12;
+       unsigned int extra_flag    : 4;
+       unsigned int ts_c          : 5;
+       unsigned int cool_dev_num  : 9;
+       struct cpumask mask[NUM_CLUSTERS];
+       struct cool_dev *cool_devs;
+       struct thermal_zone_device    *tzd;
+};
+
+static struct aml_thermal_sensor soc_sensor;
+
+int thermal_firmware_init(void)
+{
+       int err = 0;
+       unsigned char buf[4] = {0};
+       int temp;
+
+       err = efuse_read_intlItem("temper_cvbs", buf, 4);
+       if (err >= 0) {
+               pr_info("efuse buf:%02x %02x %02x %02x, err=%d\n",
+                       buf[0], buf[1], buf[2], buf[3], err);
+               temp = (buf[1] << 8) | buf[0];
+               soc_sensor.ts_c       = temp & 0x1F;
+               soc_sensor.adc_flag   = (temp & 0x8000) >> 15;
+               soc_sensor.fix_value  = (temp & 0x7fff) >> 5;
+               soc_sensor.extra_flag = (buf[3] >> 4) & 0xf;
+               pr_info("adc:%d, ts_c:%d, flag:%d, ext_flag:%x\n",
+                       soc_sensor.fix_value, soc_sensor.ts_c,
+                       soc_sensor.adc_flag,  soc_sensor.extra_flag);
+               if ((soc_sensor.extra_flag == EFUEE_PRIVATE) ||
+                   (soc_sensor.extra_flag == EFUSE_OPS)) {
+                       if (soc_sensor.adc_flag)
+                               soc_sensor.chip_trimmed = 1;
+               } else
+                       soc_sensor.chip_trimmed = 0;
+       }
+       if (soc_sensor.chip_trimmed) {
+               temp_sensor_adc_init(soc_sensor.ts_c);
+               return 0;
+       } else
+               return -1;
+
+}
+EXPORT_SYMBOL(thermal_firmware_init);
+
+int get_cpu_temp(void)
+{
+       int ret = TEMP_NOT_TRIMMED, tempa;
+
+       if (soc_sensor.chip_trimmed) {
+               ret = get_adc_sample(0, TEMP_ADC_CHANNEL);
+               if (ret >= 0) {
+                       tempa = (10 * (ret - soc_sensor.fix_value)) / 32 + 27;
+                       ret = tempa;
+               } else
+                       ret = TEMP_ADC_ERROR;
+       }
+       return ret;
+}
+EXPORT_SYMBOL(get_cpu_temp);
+
+static int get_cur_temp(void *data, int *temp)
+{
+       int val;
+
+       val = get_cpu_temp();
+       if (val == -1000)
+               return -EINVAL;
+
+       *temp = val * 1000;
+
+       return 0;
+}
+
+static int get_cool_dev_type(char *type)
+{
+       if (!strcmp(type, "cpufreq"))
+               return COOL_DEV_TYPE_CPU_FREQ;
+       if (!strcmp(type, "cpucore"))
+               return COOL_DEV_TYPE_CPU_CORE;
+       if (!strcmp(type, "gpufreq"))
+               return COOL_DEV_TYPE_GPU_FREQ;
+       if (!strcmp(type, "gpucore"))
+               return COOL_DEV_TYPE_GPU_CORE;
+       return COOL_DEV_TYPE_MAX;
+}
+
+static struct cool_dev *get_cool_dev_by_node(struct device_node *np)
+{
+       int i;
+       struct cool_dev *dev;
+
+       if (!np)
+               return NULL;
+       for (i = 0; i < soc_sensor.cool_dev_num; i++) {
+               dev = &soc_sensor.cool_devs[i];
+               if (dev->np == np)
+                       return dev;
+       }
+       return NULL;
+}
+
+int aml_thermal_min_update(struct thermal_cooling_device *cdev)
+{
+       struct gpufreq_cooling_device *gf_cdev;
+       struct gpucore_cooling_device *gc_cdev;
+       struct cool_dev *cool;
+       long min_state;
+       int i;
+       int cpu, c_id;
+
+       cool = get_cool_dev_by_node(cdev->np);
+       if (!cool)
+               return -ENODEV;
+
+       if (cool->cooling_dev == NULL)
+               cool->cooling_dev = cdev;
+
+       if (cool->min_state == 0)
+               return 0;
+
+       switch (get_cool_dev_type(cool->device_type)) {
+       case COOL_DEV_TYPE_CPU_CORE:
+               /* TODO: cluster ID */
+               cool->cooling_dev->ops->get_max_state(cdev, &min_state);
+               min_state = min_state - cool->min_state;
+               break;
+
+       case COOL_DEV_TYPE_CPU_FREQ:
+               for_each_possible_cpu(cpu) {
+                       if (mc_capable())
+                               c_id = topology_physical_package_id(cpu);
+                       else
+                               c_id = 0; /* force cluster 0 if no MC */
+                       if (c_id == cool->cluster_id)
+                               break;
+               }
+               min_state = cpufreq_cooling_get_level(cpu, cool->min_state);
+               break;
+
+       case COOL_DEV_TYPE_GPU_CORE:
+               gc_cdev = (struct gpucore_cooling_device *)cdev->devdata;
+               cdev->ops->get_max_state(cdev, &min_state);
+               min_state = min_state - cool->min_state;
+               break;
+
+       case COOL_DEV_TYPE_GPU_FREQ:
+               gf_cdev = (struct gpufreq_cooling_device *)cdev->devdata;
+               min_state = gf_cdev->get_gpu_freq_level(cool->min_state);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       for (i = 0; i < soc_sensor.tzd->trips; i++)
+               thermal_set_upper(soc_sensor.tzd, cdev, i, min_state);
+
+       return 0;
+}
+EXPORT_SYMBOL(aml_thermal_min_update);
+
+int set_cur_mode(struct thermal_zone_device *tzd, enum thermal_device_mode mode)
+{
+       int i, ret = 0;
+       struct thermal_cooling_device *cdev;
+
+       /*
+        * each cooling device should return to max state if thermal is disalbed
+        */
+       if (mode != THERMAL_DEVICE_DISABLED)
+               return 0;
+
+       for (i = 0; i < soc_sensor.cool_dev_num; i++) {
+               cdev = soc_sensor.cool_devs[i].cooling_dev;
+               if (cdev)
+                       ret |= cdev->ops->set_cur_state(cdev, 0);
+       }
+       return ret;
+}
+
+static struct thermal_zone_of_device_ops aml_thermal_ops = {
+       .get_temp = get_cur_temp,
+       .set_mode = set_cur_mode,
+};
+
+static int register_cool_dev(struct cool_dev *cool)
+{
+       int pp;
+       int id = cool->cluster_id;
+       struct cpumask *mask;
+
+       switch (get_cool_dev_type(cool->device_type)) {
+       case COOL_DEV_TYPE_CPU_CORE:
+               cool->cooling_dev = cpucore_cooling_register(cool->np,
+                                                            cool->cluster_id);
+               break;
+
+       case COOL_DEV_TYPE_CPU_FREQ:
+               mask = &soc_sensor.mask[id];
+               cool->cooling_dev = of_cpufreq_power_cooling_register(cool->np,
+                                                       mask,
+                                                       cool->coeff,
+                                                       NULL);
+               break;
+
+       /* GPU is KO, just save these parameters */
+       case COOL_DEV_TYPE_GPU_FREQ:
+               if (of_property_read_u32(cool->np, "num_of_pp", &pp))
+                       pr_err("thermal: read num_of_pp failed\n");
+               save_gpu_cool_para(cool->coeff, cool->np, pp);
+               return 0;
+
+       case COOL_DEV_TYPE_GPU_CORE:
+               save_gpucore_thermal_para(cool->np);
+               return 0;
+
+       default:
+               pr_err("thermal: unknown type:%s\n", cool->device_type);
+               return -EINVAL;
+       }
+
+       if (IS_ERR(cool->cooling_dev)) {
+               pr_err("thermal: register %s failed\n", cool->device_type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int parse_cool_device(struct device_node *np)
+{
+       int i, temp, ret = 0;
+       struct cool_dev *cool;
+       struct device_node *node, *child;
+       const char *str;
+
+       child = of_get_next_child(np, NULL);
+       for (i = 0; i < soc_sensor.cool_dev_num; i++) {
+               cool = &soc_sensor.cool_devs[i];
+               if (child == NULL)
+                       break;
+               if (of_property_read_u32(child, "min_state", &temp))
+                       pr_err("thermal: read min_state failed\n");
+               else
+                       cool->min_state = temp;
+
+               if (of_property_read_u32(child, "dyn_coeff", &temp))
+                       pr_err("thermal: read dyn_coeff failed\n");
+               else
+                       cool->coeff = temp;
+
+               if (of_property_read_u32(child, "cluster_id", &temp))
+                       pr_err("thermal: read cluster_id failed\n");
+               else
+                       cool->cluster_id = temp;
+
+               if (of_property_read_string(child, "device_type", &str))
+                       pr_err("thermal: read device_type failed\n");
+               else
+                       cool->device_type = (char *)str;
+
+               if (of_property_read_string(child, "node_name", &str))
+                       pr_err("thermal: read node_name failed\n");
+               else {
+                       node = of_find_node_by_name(NULL, str);
+                       if (!node)
+                               pr_err("thermal: can't find node\n");
+                       cool->np = node;
+               }
+               if (cool->np)
+                       ret += register_cool_dev(cool);
+               child = of_get_next_child(np, child);
+       }
+       return ret;
+}
+
+static int aml_thermal_probe(struct platform_device *pdev)
+{
+       int cpu, i, c_id;
+       struct device_node *np, *child;
+       struct cool_dev *cool;
+       struct cpufreq_policy *policy;
+
+       memset(&soc_sensor, 0, sizeof(struct aml_thermal_sensor));
+       policy = cpufreq_cpu_get(0);
+       if (!policy || !policy->freq_table) {
+               dev_info(&pdev->dev,
+                       "Frequency policy not init. Deferring probe...\n");
+               return -EPROBE_DEFER;
+       }
+
+       if (thermal_firmware_init() < 0) {
+               dev_err(&pdev->dev, "chip is not trimmed, disable thermal\n");
+               return -EINVAL;
+       }
+
+       for_each_possible_cpu(cpu) {
+               if (mc_capable())
+                       c_id = topology_physical_package_id(cpu);
+               else
+                       c_id = CLUSTER_BIG;     /* Always cluster 0 if no mc */
+               if (c_id > NUM_CLUSTERS) {
+                       pr_err("Cluster id: %d > %d\n", c_id, NUM_CLUSTERS);
+                       return -EINVAL;
+               }
+               cpumask_set_cpu(cpu, &soc_sensor.mask[c_id]);
+       }
+
+       np = pdev->dev.of_node;
+       child = of_get_child_by_name(np, "cooling_devices");
+       if (child == NULL) {
+               pr_err("thermal: can't found cooling_devices\n");
+               return -EINVAL;
+       }
+       soc_sensor.cool_dev_num = of_get_child_count(child);
+       i = sizeof(struct cool_dev) * soc_sensor.cool_dev_num;
+       soc_sensor.cool_devs = kzalloc(i, GFP_KERNEL);
+       if (soc_sensor.cool_devs == NULL) {
+               pr_err("thermal: alloc mem failed\n");
+               return -ENOMEM;
+       }
+
+       if (parse_cool_device(child))
+               return -EINVAL;
+
+       soc_sensor.tzd = thermal_zone_of_sensor_register(&pdev->dev,
+                                                         3,
+                                                         &soc_sensor,
+                                                         &aml_thermal_ops);
+
+       if (IS_ERR(soc_sensor.tzd)) {
+               dev_warn(&pdev->dev, "Error registering sensor: %p\n",
+                        soc_sensor.tzd);
+               return PTR_ERR(soc_sensor.tzd);
+       }
+
+       /* update min state for each device */
+       for (i = 0; i < soc_sensor.cool_dev_num; i++) {
+               cool = &soc_sensor.cool_devs[i];
+               if (cool->cooling_dev)
+                       aml_thermal_min_update(cool->cooling_dev);
+       }
+       thermal_zone_device_update(soc_sensor.tzd, THERMAL_EVENT_UNSPECIFIED);
+
+       return 0;
+}
+
+static int aml_thermal_remove(struct platform_device *pdev)
+{
+       kfree(soc_sensor.cool_devs);
+       return 0;
+}
+
+static const struct of_device_id aml_thermal_of_match[] = {
+       { .compatible = "amlogic, aml-thermal" },
+       {},
+};
+
+static struct platform_driver aml_thermal_platdrv = {
+       .driver = {
+               .name           = "aml-thermal",
+               .owner          = THIS_MODULE,
+               .of_match_table = aml_thermal_of_match,
+       },
+       .probe  = aml_thermal_probe,
+       .remove = aml_thermal_remove,
+};
+
+
+static int __init aml_thermal_platdrv_init(void)
+{
+       return platform_driver_register(&(aml_thermal_platdrv));
+}
+late_initcall(aml_thermal_platdrv_init);
index 93d4b4f..f3c0f8c 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/amlogic/cpucore_cooling.h>
 #include <linux/amlogic/cpu_hotplug.h>
 #include <linux/cpumask.h>
+#include <linux/amlogic/aml_thermal_hw.h>
 
 /**
  * struct cpucore_cooling_device - data for cooling device with cpucore
index 4fc18da..872b062 100644 (file)
 
 #ifndef ARCH__THERMAL_H__
 #define ARCH__THERMAL_H__
+
+#ifndef mc_capable
+#define mc_capable()           0
+#endif
+
 struct thermal_cooling_device;
 extern int thermal_firmware_init(void);
 extern int get_cpu_temp(void);