]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux...
authorLen Brown <len.brown@intel.com>
Tue, 9 Oct 2012 05:35:52 +0000 (01:35 -0400)
committerLen Brown <len.brown@intel.com>
Tue, 9 Oct 2012 05:35:52 +0000 (01:35 -0400)
Conflicts:
drivers/staging/omap-thermal/omap-thermal-common.
OMAP supplied dummy TC1 and TC2,
at the same time that the thermal tree removed them
from thermal_zone_device_register()

drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
propogate the upstream MAX_IDR_LEVEL re-name
to prevent a build failure

Previously-fixed-by: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Len Brown <len.brown@intel.com>
1  2 
drivers/acpi/thermal.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/staging/omap-thermal/omap-thermal-common.c
drivers/thermal/cpu_cooling.c
drivers/thermal/thermal_sys.c

diff --combined drivers/acpi/thermal.c
index edda74a43406b5232c01a65ac030303abab830f4,bd66bd28a43fd0885dfe42fc31efac2ef6d9137b..804204d41999d0af951086f25b37a2f7ee783a90
@@@ -106,9 -106,7 +106,9 @@@ static const struct acpi_device_id  the
  };
  MODULE_DEVICE_TABLE(acpi, thermal_device_ids);
  
 +#ifdef CONFIG_PM_SLEEP
  static int acpi_thermal_resume(struct device *dev);
 +#endif
  static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, NULL, acpi_thermal_resume);
  
  static struct acpi_driver acpi_thermal_driver = {
@@@ -708,6 -706,40 +708,40 @@@ static int thermal_get_crit_temp(struc
                return -EINVAL;
  }
  
+ static int thermal_get_trend(struct thermal_zone_device *thermal,
+                               int trip, enum thermal_trend *trend)
+ {
+       struct acpi_thermal *tz = thermal->devdata;
+       enum thermal_trip_type type;
+       int i;
+       if (thermal_get_trip_type(thermal, trip, &type))
+               return -EINVAL;
+       if (type == THERMAL_TRIP_ACTIVE) {
+               /* aggressive active cooling */
+               *trend = THERMAL_TREND_RAISING;
+               return 0;
+       }
+       /*
+        * tz->temperature has already been updated by generic thermal layer,
+        * before this callback being invoked
+        */
+       i = (tz->trips.passive.tc1 * (tz->temperature - tz->last_temperature))
+               + (tz->trips.passive.tc2
+               * (tz->temperature - tz->trips.passive.temperature));
+       if (i > 0)
+               *trend = THERMAL_TREND_RAISING;
+       else if (i < 0)
+               *trend = THERMAL_TREND_DROPPING;
+       else
+               *trend = THERMAL_TREND_STABLE;
+       return 0;
+ }
  static int thermal_notify(struct thermal_zone_device *thermal, int trip,
                           enum thermal_trip_type trip_type)
  {
        return 0;
  }
  
- typedef int (*cb)(struct thermal_zone_device *, int,
-                 struct thermal_cooling_device *);
  static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
                                        struct thermal_cooling_device *cdev,
-                                       cb action)
+                                       bool bind)
  {
        struct acpi_device *device = cdev->devdata;
        struct acpi_thermal *tz = thermal->devdata;
                    i++) {
                        handle = tz->trips.passive.devices.handles[i];
                        status = acpi_bus_get_device(handle, &dev);
-                       if (ACPI_SUCCESS(status) && (dev == device)) {
-                               result = action(thermal, trip, cdev);
-                               if (result)
-                                       goto failed;
-                       }
+                       if (ACPI_FAILURE(status) || dev != device)
+                               continue;
+                       if (bind)
+                               result =
+                                       thermal_zone_bind_cooling_device
+                                       (thermal, trip, cdev,
+                                        THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
+                       else
+                               result =
+                                       thermal_zone_unbind_cooling_device
+                                       (thermal, trip, cdev);
+                       if (result)
+                               goto failed;
                }
        }
  
                    j++) {
                        handle = tz->trips.active[i].devices.handles[j];
                        status = acpi_bus_get_device(handle, &dev);
-                       if (ACPI_SUCCESS(status) && (dev == device)) {
-                               result = action(thermal, trip, cdev);
-                               if (result)
-                                       goto failed;
-                       }
+                       if (ACPI_FAILURE(status) || dev != device)
+                               continue;
+                       if (bind)
+                               result = thermal_zone_bind_cooling_device
+                                       (thermal, trip, cdev,
+                                        THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
+                       else
+                               result = thermal_zone_unbind_cooling_device
+                                       (thermal, trip, cdev);
+                       if (result)
+                               goto failed;
                }
        }
  
                handle = tz->devices.handles[i];
                status = acpi_bus_get_device(handle, &dev);
                if (ACPI_SUCCESS(status) && (dev == device)) {
-                       result = action(thermal, -1, cdev);
+                       if (bind)
+                               result = thermal_zone_bind_cooling_device
+                                               (thermal, -1, cdev,
+                                                THERMAL_NO_LIMIT,
+                                                THERMAL_NO_LIMIT);
+                       else
+                               result = thermal_zone_unbind_cooling_device
+                                               (thermal, -1, cdev);
                        if (result)
                                goto failed;
                }
@@@ -802,16 -853,14 +855,14 @@@ static in
  acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal,
                                        struct thermal_cooling_device *cdev)
  {
-       return acpi_thermal_cooling_device_cb(thermal, cdev,
-                               thermal_zone_bind_cooling_device);
+       return acpi_thermal_cooling_device_cb(thermal, cdev, true);
  }
  
  static int
  acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
                                        struct thermal_cooling_device *cdev)
  {
-       return acpi_thermal_cooling_device_cb(thermal, cdev,
-                               thermal_zone_unbind_cooling_device);
+       return acpi_thermal_cooling_device_cb(thermal, cdev, false);
  }
  
  static const struct thermal_zone_device_ops acpi_thermal_zone_ops = {
        .get_trip_type = thermal_get_trip_type,
        .get_trip_temp = thermal_get_trip_temp,
        .get_crit_temp = thermal_get_crit_temp,
+       .get_trend = thermal_get_trend,
        .notify = thermal_notify,
  };
  
@@@ -849,15 -899,12 +901,12 @@@ static int acpi_thermal_register_therma
                tz->thermal_zone =
                        thermal_zone_device_register("acpitz", trips, 0, tz,
                                                     &acpi_thermal_zone_ops,
-                                                    tz->trips.passive.tc1,
-                                                    tz->trips.passive.tc2,
                                                     tz->trips.passive.tsp*100,
                                                     tz->polling_frequency*100);
        else
                tz->thermal_zone =
                        thermal_zone_device_register("acpitz", trips, 0, tz,
-                                                    &acpi_thermal_zone_ops,
-                                                    0, 0, 0,
+                                                    &acpi_thermal_zone_ops, 0,
                                                     tz->polling_frequency*100);
        if (IS_ERR(tz->thermal_zone))
                return -ENODEV;
@@@ -1043,7 -1090,6 +1092,7 @@@ static int acpi_thermal_remove(struct a
        return 0;
  }
  
 +#ifdef CONFIG_PM_SLEEP
  static int acpi_thermal_resume(struct device *dev)
  {
        struct acpi_thermal *tz;
  
        return AE_OK;
  }
 +#endif
  
  static int thermal_act(const struct dmi_system_id *d) {
  
diff --combined drivers/hwmon/Kconfig
index c74e73b2069ad230cd1be4ae4d7510252d44f52b,84e02b416a4ae11cd4a6745de431a0bc61b02583..c4633de64465a2eccc5d0305238feee8a8c28375
@@@ -41,7 -41,7 +41,7 @@@ comment "Native drivers
  
  config SENSORS_ABITUGURU
        tristate "Abit uGuru (rev 1 & 2)"
 -      depends on X86 && DMI && EXPERIMENTAL
 +      depends on X86 && DMI
        help
          If you say yes here you get support for the sensor part of the first
          and second revision of the Abit uGuru chip. The voltage and frequency
@@@ -56,7 -56,7 +56,7 @@@
  
  config SENSORS_ABITUGURU3
        tristate "Abit uGuru (rev 3)"
 -      depends on X86 && DMI && EXPERIMENTAL
 +      depends on X86 && DMI
        help
          If you say yes here you get support for the sensor part of the
          third revision of the Abit uGuru chip. Only reading the sensors
@@@ -70,7 -70,7 +70,7 @@@
  
  config SENSORS_AD7314
        tristate "Analog Devices AD7314 and compatibles"
 -      depends on SPI && EXPERIMENTAL
 +      depends on SPI
        help
          If you say yes here you get support for the Analog Devices
          AD7314, ADT7301 and ADT7302 temperature sensors.
@@@ -80,7 -80,7 +80,7 @@@
  
  config SENSORS_AD7414
        tristate "Analog Devices AD7414"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        help
          If you say yes here you get support for the Analog Devices
          AD7414 temperature monitoring chip.
@@@ -90,7 -90,7 +90,7 @@@
  
  config SENSORS_AD7418
        tristate "Analog Devices AD7416, AD7417 and AD7418"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        help
          If you say yes here you get support for the Analog Devices
          AD7416, AD7417 and AD7418 temperature monitoring chips.
  
  config SENSORS_ADCXX
        tristate "National Semiconductor ADCxxxSxxx"
 -      depends on SPI_MASTER && EXPERIMENTAL
 +      depends on SPI_MASTER
        help
          If you say yes here you get support for the National Semiconductor
          ADC<bb><c>S<sss> chip family, where
@@@ -179,19 -179,9 +179,19 @@@ config SENSORS_ADM924
          This driver can also be built as a module.  If so, the module
          will be called adm9240.
  
 +config SENSORS_ADT7410
 +      tristate "Analog Devices ADT7410"
 +      depends on I2C
 +      help
 +        If you say yes here you get support for the Analog Devices
 +        ADT7410 temperature monitoring chip.
 +
 +        This driver can also be built as a module. If so, the module
 +        will be called adt7410.
 +
  config SENSORS_ADT7411
        tristate "Analog Devices ADT7411"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        help
          If you say yes here you get support for the Analog Devices
          ADT7411 voltage and temperature monitoring chip.
  
  config SENSORS_ADT7462
        tristate "Analog Devices ADT7462"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        help
          If you say yes here you get support for the Analog Devices
          ADT7462 temperature monitoring chips.
  
  config SENSORS_ADT7470
        tristate "Analog Devices ADT7470"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        help
          If you say yes here you get support for the Analog Devices
          ADT7470 temperature monitoring chips.
@@@ -246,7 -236,7 +246,7 @@@ config SENSORS_ASC762
  
  config SENSORS_K8TEMP
        tristate "AMD Athlon64/FX or Opteron temperature sensor"
 -      depends on X86 && PCI && EXPERIMENTAL
 +      depends on X86 && PCI
        help
          If you say yes here you get support for the temperature
          sensor(s) inside your CPU. Supported is whole AMD K8
@@@ -281,7 -271,7 +281,7 @@@ config SENSORS_FAM15H_POWE
  
  config SENSORS_ASB100
        tristate "Asus ASB100 Bach"
 -      depends on X86 && I2C && EXPERIMENTAL
 +      depends on X86 && I2C
        select HWMON_VID
        help
          If you say yes here you get support for the ASB100 Bach sensor
  
  config SENSORS_ATXP1
        tristate "Attansic ATXP1 VID controller"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        select HWMON_VID
        help
          If you say yes here you get support for the Attansic ATXP1 VID
@@@ -334,19 -324,9 +334,9 @@@ config SENSORS_DA9052_AD
          This driver can also be built as module. If so, the module
          will be called da9052-hwmon.
  
- config SENSORS_EXYNOS4_TMU
-       tristate "Temperature sensor on Samsung EXYNOS4"
-       depends on ARCH_EXYNOS4
-       help
-         If you say yes here you get support for TMU (Thermal Management
-         Unit) on SAMSUNG EXYNOS4 series of SoC.
-         This driver can also be built as a module. If so, the module
-         will be called exynos4-tmu.
  config SENSORS_I5K_AMB
        tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets"
 -      depends on PCI && EXPERIMENTAL
 +      depends on PCI
        help
          If you say yes here you get support for FB-DIMM AMB temperature
          monitoring chips on systems with the Intel 5000 series chipset.
@@@ -455,7 -435,7 +445,7 @@@ config SENSORS_GPIO_FA
  
  config SENSORS_HIH6130
        tristate "Honeywell Humidicon HIH-6130 humidity/temperature sensor"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        help
          If you say yes here you get support for Honeywell Humidicon
          HIH-6130 and HIH-6131 Humidicon humidity sensors.
  
  config SENSORS_CORETEMP
        tristate "Intel Core/Core2/Atom temperature sensor"
 -      depends on X86 && PCI && EXPERIMENTAL
 +      depends on X86 && PCI
        help
          If you say yes here you get support for the temperature
          sensor inside your CPU. Most of the family 6 CPUs
@@@ -505,8 -485,8 +495,8 @@@ config SENSORS_IT8
        select HWMON_VID
        help
          If you say yes here you get support for ITE IT8705F, IT8712F,
 -        IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F and IT8758E
 -        sensor chips, and the SiS960 clone.
 +        IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E,
 +        IT8782F, and IT8783E/F sensor chips, and the SiS950 clone.
  
          This driver can also be built as a module.  If so, the module
          will be called it87.
@@@ -537,7 -517,7 +527,7 @@@ config SENSORS_JC4
  
  config SENSORS_LINEAGE
        tristate "Lineage Compact Power Line Power Entry Module"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        help
          If you say yes here you get support for the Lineage Compact Power Line
          series of DC/DC and AC/DC converters such as CP1800, CP2000AC,
@@@ -560,12 -540,12 +550,12 @@@ config SENSORS_LM6
          will be called lm63.
  
  config SENSORS_LM70
 -      tristate "National Semiconductor LM70 / Texas Instruments TMP121"
 +      tristate "National Semiconductor LM70 and compatibles"
        depends on SPI_MASTER
        help
          If you say yes here you get support for the National Semiconductor
 -        LM70 and Texas Instruments TMP121/TMP123 digital temperature
 -        sensor chips.
 +        LM70, LM71, LM74 and Texas Instruments TMP121/TMP123 digital tempera-
 +        ture sensor chips.
  
          This driver can also be built as a module.  If so, the module
          will be called lm70.
@@@ -719,7 -699,7 +709,7 @@@ config SENSORS_LTC415
  
  config SENSORS_LTC4215
        tristate "Linear Technology LTC4215"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        default n
        help
          If you say yes here you get support for Linear Technology LTC4215
  
  config SENSORS_LTC4245
        tristate "Linear Technology LTC4245"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        default n
        help
          If you say yes here you get support for Linear Technology LTC4245
  
  config SENSORS_LTC4261
        tristate "Linear Technology LTC4261"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        default n
        help
          If you say yes here you get support for Linear Technology LTC4261
@@@ -762,7 -742,7 +752,7 @@@ config SENSORS_LM9524
  
  config SENSORS_LM95245
        tristate "National Semiconductor LM95245 sensor chip"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        help
          If you say yes here you get support for LM95245 sensor chip.
  
          will be called lm95245.
  
  config SENSORS_MAX1111
 -      tristate "Maxim MAX1111 Multichannel, Serial 8-bit ADC chip"
 +      tristate "Maxim MAX1111 Serial 8-bit ADC chip and compatibles"
        depends on SPI_MASTER
        help
 -        Say y here to support Maxim's MAX1111 ADC chips.
 +        Say y here to support Maxim's MAX1110, MAX1111, MAX1112, and MAX1113
 +        ADC chips.
  
          This driver can also be built as a module.  If so, the module
          will be called max1111.
@@@ -806,7 -785,7 +796,7 @@@ config SENSORS_MAX161
  
  config SENSORS_MAX1668
        tristate "Maxim MAX1668 and compatibles"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        help
          If you say yes here you get support for MAX1668, MAX1989 and
          MAX1805 chips.
          This driver can also be built as a module.  If so, the module
          will be called max1668.
  
 +config SENSORS_MAX197
 +      tristate "Maxim MAX197 and compatibles"
 +      help
 +        Support for the Maxim MAX197 A/D converter.
 +        Support will include, but not be limited to, MAX197, and MAX199.
 +
 +        This driver can also be built as a module. If so, the module
 +        will be called max197.
 +
  config SENSORS_MAX6639
        tristate "Maxim MAX6639 sensor chip"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        help
          If you say yes here you get support for the MAX6639
          sensor chips.
  
  config SENSORS_MAX6642
        tristate "Maxim MAX6642 sensor chip"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        help
          If you say yes here you get support for MAX6642 sensor chip.
          MAX6642 is a SMBus-Compatible Remote/Local Temperature Sensor
  
  config SENSORS_MAX6650
        tristate "Maxim MAX6650 sensor chip"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        help
          If you say yes here you get support for the MAX6650 / MAX6651
          sensor chips.
          will be called max6650.
  
  config SENSORS_MCP3021
 -      tristate "Microchip MCP3021"
 -      depends on I2C && EXPERIMENTAL
 +      tristate "Microchip MCP3021 and compatibles"
 +      depends on I2C
        help
 -        If you say yes here you get support for the MCP3021 chip
 -        that is a A/D converter (ADC) with 10-bit resolution.
 +        If you say yes here you get support for MCP3021 and MCP3221.
 +        The MCP3021 is a A/D converter (ADC) with 10-bit and the MCP3221
 +        with 12-bit resolution.
  
          This driver can also be built as a module.  If so, the module
          will be called mcp3021.
  
  config SENSORS_NTC_THERMISTOR
        tristate "NTC thermistor support"
 -      depends on EXPERIMENTAL
        help
          This driver supports NTC thermistors sensor reading and its
          interpretation. The driver can also monitor the temperature and
@@@ -971,7 -941,7 +961,7 @@@ config SENSORS_SIS559
  
  config SENSORS_SMM665
        tristate "Summit Microelectronics SMM665"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        default n
        help
          If you say yes here you get support for the hardware monitoring
  
  config SENSORS_DME1737
        tristate "SMSC DME1737, SCH311x and compatibles"
 -      depends on I2C && EXPERIMENTAL && !PPC
 +      depends on I2C && !PPC
        select HWMON_VID
        help
          If you say yes here you get support for the hardware monitoring
@@@ -1062,7 -1032,7 +1052,7 @@@ config SENSORS_SMSC47M19
  
  config SENSORS_SMSC47B397
        tristate "SMSC LPC47B397-NC"
 -      depends on EXPERIMENTAL && !PPC
 +      depends on !PPC
        help
          If you say yes here you get support for the SMSC LPC47B397-NC
          sensor chip.
@@@ -1136,7 -1106,7 +1126,7 @@@ config SENSORS_ADS787
  
  config SENSORS_AMC6821
        tristate "Texas Instruments AMC6821"
 -      depends on I2C  && EXPERIMENTAL
 +      depends on I2C 
        help
          If you say yes here you get support for the Texas Instruments
          AMC6821 hardware monitoring chips.
          will be called amc6821.
  
  config SENSORS_INA2XX
 -      tristate "Texas Instruments INA219, INA226"
 -      depends on I2C && EXPERIMENTAL
 +      tristate "Texas Instruments INA219 and compatibles"
 +      depends on I2C
        help
 -        If you say yes here you get support for INA219 and INA226 power
 -        monitor chips.
 +        If you say yes here you get support for INA219, INA220, INA226, and
 +        INA230 power monitor chips.
  
          The INA2xx driver is configured for the default configuration of
          the part as described in the datasheet.
@@@ -1169,7 -1139,7 +1159,7 @@@ config SENSORS_THMC5
  
  config SENSORS_TMP102
        tristate "Texas Instruments TMP102"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        help
          If you say yes here you get support for Texas Instruments TMP102
          sensor chips.
  
  config SENSORS_TMP401
        tristate "Texas Instruments TMP401 and compatibles"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        help
          If you say yes here you get support for Texas Instruments TMP401 and
          TMP411 temperature sensor chips.
  
  config SENSORS_TMP421
        tristate "Texas Instruments TMP421 and compatible"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        help
          If you say yes here you get support for Texas Instruments TMP421,
          TMP422 and TMP423 temperature sensor chips.
@@@ -1281,7 -1251,7 +1271,7 @@@ config SENSORS_W83792
  
  config SENSORS_W83793
        tristate "Winbond W83793"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        select HWMON_VID
        help
          If you say yes here you get support for the Winbond W83793
  
  config SENSORS_W83795
        tristate "Winbond/Nuvoton W83795G/ADG"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        help
          If you say yes here you get support for the Winbond W83795G and
          W83795ADG hardware monitoring chip, including manual fan speed
  
  config SENSORS_W83795_FANCTRL
        boolean "Include automatic fan control support (DANGEROUS)"
 -      depends on SENSORS_W83795 && EXPERIMENTAL
 +      depends on SENSORS_W83795
        default n
        help
          If you say yes here, support for automatic fan speed control
  
  config SENSORS_W83L785TS
        tristate "Winbond W83L785TS-S"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        help
          If you say yes here you get support for the Winbond W83L785TS-S
          sensor chip, which is used on the Asus A7N8X, among other
  
  config SENSORS_W83L786NG
        tristate "Winbond W83L786NG, W83L786NR"
 -      depends on I2C && EXPERIMENTAL
 +      depends on I2C
        help
          If you say yes here you get support for the Winbond W83L786NG
          and W83L786NR sensor chips.
@@@ -1447,7 -1417,7 +1437,7 @@@ config SENSORS_ACPI_POWE
  
  config SENSORS_ATK0110
        tristate "ASUS ATK0110"
 -      depends on X86 && EXPERIMENTAL
 +      depends on X86
        help
          If you say yes here you get support for the ACPI hardware
          monitoring interface found in many ASUS motherboards. This
diff --combined drivers/hwmon/Makefile
index a62ce17ddbfcb2c41c62af1e1c629303420bb80f,3eafe483f36a53d367c58feaa6dea9484c85a7bd..8d5fcb5e8e9f479438cfb3e6927906e0abd214cf
@@@ -34,7 -34,6 +34,7 @@@ obj-$(CONFIG_SENSORS_ADM9240) += adm924
  obj-$(CONFIG_SENSORS_ADS1015) += ads1015.o
  obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o
  obj-$(CONFIG_SENSORS_ADS7871) += ads7871.o
 +obj-$(CONFIG_SENSORS_ADT7410) += adt7410.o
  obj-$(CONFIG_SENSORS_ADT7411) += adt7411.o
  obj-$(CONFIG_SENSORS_ADT7462) += adt7462.o
  obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o
@@@ -50,7 -49,6 +50,6 @@@ obj-$(CONFIG_SENSORS_DS1621)  += ds1621.
  obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o
  obj-$(CONFIG_SENSORS_EMC2103) += emc2103.o
  obj-$(CONFIG_SENSORS_EMC6W201)        += emc6w201.o
- obj-$(CONFIG_SENSORS_EXYNOS4_TMU)     += exynos4_tmu.o
  obj-$(CONFIG_SENSORS_F71805F) += f71805f.o
  obj-$(CONFIG_SENSORS_F71882FG)        += f71882fg.o
  obj-$(CONFIG_SENSORS_F75375S) += f75375s.o
@@@ -95,7 -93,6 +94,7 @@@ obj-$(CONFIG_SENSORS_MAX1111) += max111
  obj-$(CONFIG_SENSORS_MAX16065)        += max16065.o
  obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
  obj-$(CONFIG_SENSORS_MAX1668) += max1668.o
 +obj-$(CONFIG_SENSORS_MAX197)  += max197.o
  obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
  obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
  obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
index 46ee0a9f49d92dfb43344b95856e53adf3462dd6,b4cd6ccf4e2df6b56c77de5889cc08f610e3fe1a..5c0c203b887f41d5d4d6bdf4709ccd7244640072
@@@ -77,16 -77,10 +77,16 @@@ static inline int omap_thermal_get_temp
                                         unsigned long *temp)
  {
        struct omap_thermal_data *data = thermal->devdata;
 -      struct omap_bandgap *bg_ptr = data->bg_ptr;
 -      struct omap_temp_sensor *s = &bg_ptr->conf->sensors[data->sensor_id];
 +      struct omap_bandgap *bg_ptr;
 +      struct omap_temp_sensor *s;
        int ret, tmp, pcb_temp, slope, constant;
  
 +      if (!data)
 +              return 0;
 +
 +      bg_ptr = data->bg_ptr;
 +      s = &bg_ptr->conf->sensors[data->sensor_id];
 +
        ret = omap_bandgap_read_temperature(bg_ptr, data->sensor_id, &tmp);
        if (ret)
                return ret;
@@@ -126,7 -120,9 +126,9 @@@ static int omap_thermal_bind(struct the
  
        /* TODO: bind with min and max states */
        /* Simple thing, two trips, one passive another critical */
-       return thermal_zone_bind_cooling_device(thermal, 0, cdev);
+       return thermal_zone_bind_cooling_device(thermal, 0, cdev,
+                                               THERMAL_NO_LIMIT,
+                                               THERMAL_NO_LIMIT);
  }
  
  /* Unbind callback functions for thermal zone */
@@@ -233,44 -229,26 +235,43 @@@ static struct thermal_zone_device_ops o
        .get_crit_temp = omap_thermal_get_crit_temp,
  };
  
 -int omap_thermal_expose_sensor(struct omap_bandgap *bg_ptr, int id,
 -                             char *domain)
 +static struct omap_thermal_data
 +*omap_thermal_build_data(struct omap_bandgap *bg_ptr, int id)
  {
        struct omap_thermal_data *data;
  
        data = devm_kzalloc(bg_ptr->dev, sizeof(*data), GFP_KERNEL);
        if (!data) {
                dev_err(bg_ptr->dev, "kzalloc fail\n");
 -              return -ENOMEM;
 +              return NULL;
        }
        data->sensor_id = id;
        data->bg_ptr = bg_ptr;
        data->mode = THERMAL_DEVICE_ENABLED;
        INIT_WORK(&data->thermal_wq, omap_thermal_work);
  
 +      return data;
 +}
 +
 +int omap_thermal_expose_sensor(struct omap_bandgap *bg_ptr, int id,
 +                             char *domain)
 +{
 +      struct omap_thermal_pdata pdata;
 +
 +      data = omap_bandgap_get_sensor_data(bg_ptr, id);
 +
 +      if (!data)
 +              data = omap_thermal_build_pdata(bg_ptr, id);
 +
 +      if (!data)
 +              return -EINVAL;
 +
        /* TODO: remove TC1 TC2 */
        /* Create thermal zone */
        data->omap_thermal = thermal_zone_device_register(domain,
                                OMAP_TRIP_NUMBER, 0, data, &omap_thermal_ops,
-                               1, 2, /*TODO: remove this when FW allows */
 -                              0, FAST_TEMP_MONITORING_RATE);
 +                              FAST_TEMP_MONITORING_RATE,
 +                              FAST_TEMP_MONITORING_RATE);
        if (IS_ERR_OR_NULL(data->omap_thermal)) {
                dev_err(bg_ptr->dev, "thermal zone device is NULL\n");
                return PTR_ERR(data->omap_thermal);
@@@ -357,11 -335,6 +358,11 @@@ int omap_thermal_register_cpu_cooling(s
        int tab_size, ret;
  
        data = omap_bandgap_get_sensor_data(bg_ptr, id);
 +      if (!data)
 +              data = omap_thermal_build_pdata(bg_ptr, id);
 +
 +      if (!data)
 +              return -EINVAL;
  
        ret = omap_thermal_build_cpufreq_clip(bg_ptr, &tab_ptr, &tab_size);
        if (ret < 0) {
                return PTR_ERR(data->cool_dev);
        }
        bg_ptr->conf->sensors[id].cooling_data.freq_clip_count = tab_size;
 +      omap_bandgap_set_sensor_data(bg_ptr, id, data);
  
        return 0;
  }
index 0000000000000000000000000000000000000000,9050c1b0573cd8f9f29221afb50c1aa57b491d3c..cc1c930a90e4b5a5c9cd39c6e66aa1aea79513b9
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,449 +1,449 @@@
 -      *id = *id & MAX_ID_MASK;
+ /*
+  *  linux/drivers/thermal/cpu_cooling.c
+  *
+  *  Copyright (C) 2012        Samsung Electronics Co., Ltd(http://www.samsung.com)
+  *  Copyright (C) 2012  Amit Daniel <amit.kachhap@linaro.org>
+  *
+  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  *  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; version 2 of the License.
+  *
+  *  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.
+  *
+  *  You should have received a copy of the GNU General Public License along
+  *  with this program; if not, write to the Free Software Foundation, Inc.,
+  *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+  *
+  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  */
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/thermal.h>
+ #include <linux/platform_device.h>
+ #include <linux/cpufreq.h>
+ #include <linux/err.h>
+ #include <linux/slab.h>
+ #include <linux/cpu.h>
+ #include <linux/cpu_cooling.h>
+ /**
+  * struct cpufreq_cooling_device
+  * @id: unique integer value corresponding to each cpufreq_cooling_device
+  *    registered.
+  * @cool_dev: thermal_cooling_device pointer to keep track of the the
+  *    egistered cooling device.
+  * @cpufreq_state: integer value representing the current state of cpufreq
+  *    cooling devices.
+  * @cpufreq_val: integer value representing the absolute value of the clipped
+  *    frequency.
+  * @allowed_cpus: all the cpus involved for this cpufreq_cooling_device.
+  * @node: list_head to link all cpufreq_cooling_device together.
+  *
+  * This structure is required for keeping information of each
+  * cpufreq_cooling_device registered as a list whose head is represented by
+  * cooling_cpufreq_list. In order to prevent corruption of this list a
+  * mutex lock cooling_cpufreq_lock is used.
+  */
+ struct cpufreq_cooling_device {
+       int id;
+       struct thermal_cooling_device *cool_dev;
+       unsigned int cpufreq_state;
+       unsigned int cpufreq_val;
+       struct cpumask allowed_cpus;
+       struct list_head node;
+ };
+ static LIST_HEAD(cooling_cpufreq_list);
+ static DEFINE_IDR(cpufreq_idr);
+ static struct mutex cooling_cpufreq_lock;
+ /* notify_table passes value to the CPUFREQ_ADJUST callback function. */
+ #define NOTIFY_INVALID NULL
+ struct cpufreq_cooling_device *notify_device;
+ /**
+  * get_idr - function to get a unique id.
+  * @idr: struct idr * handle used to create a id.
+  * @id: int * value generated by this function.
+  */
+ static int get_idr(struct idr *idr, int *id)
+ {
+       int err;
+ again:
+       if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
+               return -ENOMEM;
+       mutex_lock(&cooling_cpufreq_lock);
+       err = idr_get_new(idr, NULL, id);
+       mutex_unlock(&cooling_cpufreq_lock);
+       if (unlikely(err == -EAGAIN))
+               goto again;
+       else if (unlikely(err))
+               return err;
++      *id = *id & MAX_IDR_MASK;
+       return 0;
+ }
+ /**
+  * release_idr - function to free the unique id.
+  * @idr: struct idr * handle used for creating the id.
+  * @id: int value representing the unique id.
+  */
+ static void release_idr(struct idr *idr, int id)
+ {
+       mutex_lock(&cooling_cpufreq_lock);
+       idr_remove(idr, id);
+       mutex_unlock(&cooling_cpufreq_lock);
+ }
+ /* Below code defines functions to be used for cpufreq as cooling device */
+ /**
+  * is_cpufreq_valid - function to check if a cpu has frequency transition policy.
+  * @cpu: cpu for which check is needed.
+  */
+ static int is_cpufreq_valid(int cpu)
+ {
+       struct cpufreq_policy policy;
+       return !cpufreq_get_policy(&policy, cpu);
+ }
+ /**
+  * get_cpu_frequency - get the absolute value of frequency from level.
+  * @cpu: cpu for which frequency is fetched.
+  * @level: level of frequency of the CPU
+  *    e.g level=1 --> 1st MAX FREQ, LEVEL=2 ---> 2nd MAX FREQ, .... etc
+  */
+ static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level)
+ {
+       int ret = 0, i = 0;
+       unsigned long level_index;
+       bool descend = false;
+       struct cpufreq_frequency_table *table =
+                                       cpufreq_frequency_get_table(cpu);
+       if (!table)
+               return ret;
+       while (table[i].frequency != CPUFREQ_TABLE_END) {
+               if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
+                       continue;
+               /*check if table in ascending or descending order*/
+               if ((table[i + 1].frequency != CPUFREQ_TABLE_END) &&
+                       (table[i + 1].frequency < table[i].frequency)
+                       && !descend) {
+                       descend = true;
+               }
+               /*return if level matched and table in descending order*/
+               if (descend && i == level)
+                       return table[i].frequency;
+               i++;
+       }
+       i--;
+       if (level > i || descend)
+               return ret;
+       level_index = i - level;
+       /*Scan the table in reverse order and match the level*/
+       while (i >= 0) {
+               if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
+                       continue;
+               /*return if level matched*/
+               if (i == level_index)
+                       return table[i].frequency;
+               i--;
+       }
+       return ret;
+ }
+ /**
+  * cpufreq_apply_cooling - function to apply frequency clipping.
+  * @cpufreq_device: cpufreq_cooling_device pointer containing frequency
+  *    clipping data.
+  * @cooling_state: value of the cooling state.
+  */
+ static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device,
+                               unsigned long cooling_state)
+ {
+       unsigned int cpuid, clip_freq;
+       struct cpumask *maskPtr = &cpufreq_device->allowed_cpus;
+       unsigned int cpu = cpumask_any(maskPtr);
+       /* Check if the old cooling action is same as new cooling action */
+       if (cpufreq_device->cpufreq_state == cooling_state)
+               return 0;
+       clip_freq = get_cpu_frequency(cpu, cooling_state);
+       if (!clip_freq)
+               return -EINVAL;
+       cpufreq_device->cpufreq_state = cooling_state;
+       cpufreq_device->cpufreq_val = clip_freq;
+       notify_device = cpufreq_device;
+       for_each_cpu(cpuid, maskPtr) {
+               if (is_cpufreq_valid(cpuid))
+                       cpufreq_update_policy(cpuid);
+       }
+       notify_device = NOTIFY_INVALID;
+       return 0;
+ }
+ /**
+  * cpufreq_thermal_notifier - notifier callback for cpufreq policy change.
+  * @nb:       struct notifier_block * with callback info.
+  * @event: value showing cpufreq event for which this function invoked.
+  * @data: callback-specific data
+  */
+ static int cpufreq_thermal_notifier(struct notifier_block *nb,
+                                       unsigned long event, void *data)
+ {
+       struct cpufreq_policy *policy = data;
+       unsigned long max_freq = 0;
+       if (event != CPUFREQ_ADJUST || notify_device == NOTIFY_INVALID)
+               return 0;
+       if (cpumask_test_cpu(policy->cpu, &notify_device->allowed_cpus))
+               max_freq = notify_device->cpufreq_val;
+       /* Never exceed user_policy.max*/
+       if (max_freq > policy->user_policy.max)
+               max_freq = policy->user_policy.max;
+       if (policy->max != max_freq)
+               cpufreq_verify_within_limits(policy, 0, max_freq);
+       return 0;
+ }
+ /*
+  * cpufreq cooling device callback functions are defined below
+  */
+ /**
+  * cpufreq_get_max_state - callback function to get the max cooling state.
+  * @cdev: thermal cooling device pointer.
+  * @state: fill this variable with the max cooling state.
+  */
+ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
+                                unsigned long *state)
+ {
+       int ret = -EINVAL, i = 0;
+       struct cpufreq_cooling_device *cpufreq_device;
+       struct cpumask *maskPtr;
+       unsigned int cpu;
+       struct cpufreq_frequency_table *table;
+       mutex_lock(&cooling_cpufreq_lock);
+       list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
+               if (cpufreq_device && cpufreq_device->cool_dev == cdev)
+                       break;
+       }
+       if (cpufreq_device == NULL)
+               goto return_get_max_state;
+       maskPtr = &cpufreq_device->allowed_cpus;
+       cpu = cpumask_any(maskPtr);
+       table = cpufreq_frequency_get_table(cpu);
+       if (!table) {
+               *state = 0;
+               ret = 0;
+               goto return_get_max_state;
+       }
+       while (table[i].frequency != CPUFREQ_TABLE_END) {
+               if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
+                       continue;
+               i++;
+       }
+       if (i > 0) {
+               *state = --i;
+               ret = 0;
+       }
+ return_get_max_state:
+       mutex_unlock(&cooling_cpufreq_lock);
+       return ret;
+ }
+ /**
+  * cpufreq_get_cur_state - callback function to get the current cooling state.
+  * @cdev: thermal cooling device pointer.
+  * @state: fill this variable with the current cooling state.
+  */
+ static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
+                                unsigned long *state)
+ {
+       int ret = -EINVAL;
+       struct cpufreq_cooling_device *cpufreq_device;
+       mutex_lock(&cooling_cpufreq_lock);
+       list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
+               if (cpufreq_device && cpufreq_device->cool_dev == cdev) {
+                       *state = cpufreq_device->cpufreq_state;
+                       ret = 0;
+                       break;
+               }
+       }
+       mutex_unlock(&cooling_cpufreq_lock);
+       return ret;
+ }
+ /**
+  * cpufreq_set_cur_state - callback function to set the current cooling state.
+  * @cdev: thermal cooling device pointer.
+  * @state: set this variable to the current cooling state.
+  */
+ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
+                                unsigned long state)
+ {
+       int ret = -EINVAL;
+       struct cpufreq_cooling_device *cpufreq_device;
+       mutex_lock(&cooling_cpufreq_lock);
+       list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
+               if (cpufreq_device && cpufreq_device->cool_dev == cdev) {
+                       ret = 0;
+                       break;
+               }
+       }
+       if (!ret)
+               ret = cpufreq_apply_cooling(cpufreq_device, state);
+       mutex_unlock(&cooling_cpufreq_lock);
+       return ret;
+ }
+ /* Bind cpufreq callbacks to thermal cooling device ops */
+ static struct thermal_cooling_device_ops const cpufreq_cooling_ops = {
+       .get_max_state = cpufreq_get_max_state,
+       .get_cur_state = cpufreq_get_cur_state,
+       .set_cur_state = cpufreq_set_cur_state,
+ };
+ /* Notifier for cpufreq policy change */
+ static struct notifier_block thermal_cpufreq_notifier_block = {
+       .notifier_call = cpufreq_thermal_notifier,
+ };
+ /**
+  * cpufreq_cooling_register - function to create cpufreq cooling device.
+  * @clip_cpus: cpumask of cpus where the frequency constraints will happen.
+  */
+ struct thermal_cooling_device *cpufreq_cooling_register(
+       struct cpumask *clip_cpus)
+ {
+       struct thermal_cooling_device *cool_dev;
+       struct cpufreq_cooling_device *cpufreq_dev = NULL;
+       unsigned int cpufreq_dev_count = 0, min = 0, max = 0;
+       char dev_name[THERMAL_NAME_LENGTH];
+       int ret = 0, i;
+       struct cpufreq_policy policy;
+       list_for_each_entry(cpufreq_dev, &cooling_cpufreq_list, node)
+               cpufreq_dev_count++;
+       /*Verify that all the clip cpus have same freq_min, freq_max limit*/
+       for_each_cpu(i, clip_cpus) {
+               /*continue if cpufreq policy not found and not return error*/
+               if (!cpufreq_get_policy(&policy, i))
+                       continue;
+               if (min == 0 && max == 0) {
+                       min = policy.cpuinfo.min_freq;
+                       max = policy.cpuinfo.max_freq;
+               } else {
+                       if (min != policy.cpuinfo.min_freq ||
+                               max != policy.cpuinfo.max_freq)
+                               return ERR_PTR(-EINVAL);
+ }
+       }
+       cpufreq_dev = kzalloc(sizeof(struct cpufreq_cooling_device),
+                       GFP_KERNEL);
+       if (!cpufreq_dev)
+               return ERR_PTR(-ENOMEM);
+       cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus);
+       if (cpufreq_dev_count == 0)
+               mutex_init(&cooling_cpufreq_lock);
+       ret = get_idr(&cpufreq_idr, &cpufreq_dev->id);
+       if (ret) {
+               kfree(cpufreq_dev);
+               return ERR_PTR(-EINVAL);
+       }
+       sprintf(dev_name, "thermal-cpufreq-%d", cpufreq_dev->id);
+       cool_dev = thermal_cooling_device_register(dev_name, cpufreq_dev,
+                                               &cpufreq_cooling_ops);
+       if (!cool_dev) {
+               release_idr(&cpufreq_idr, cpufreq_dev->id);
+               kfree(cpufreq_dev);
+               return ERR_PTR(-EINVAL);
+       }
+       cpufreq_dev->cool_dev = cool_dev;
+       cpufreq_dev->cpufreq_state = 0;
+       mutex_lock(&cooling_cpufreq_lock);
+       list_add_tail(&cpufreq_dev->node, &cooling_cpufreq_list);
+       /* Register the notifier for first cpufreq cooling device */
+       if (cpufreq_dev_count == 0)
+               cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
+                                               CPUFREQ_POLICY_NOTIFIER);
+       mutex_unlock(&cooling_cpufreq_lock);
+       return cool_dev;
+ }
+ EXPORT_SYMBOL(cpufreq_cooling_register);
+ /**
+  * cpufreq_cooling_unregister - function to remove cpufreq cooling device.
+  * @cdev: thermal cooling device pointer.
+  */
+ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
+ {
+       struct cpufreq_cooling_device *cpufreq_dev = NULL;
+       unsigned int cpufreq_dev_count = 0;
+       mutex_lock(&cooling_cpufreq_lock);
+       list_for_each_entry(cpufreq_dev, &cooling_cpufreq_list, node) {
+               if (cpufreq_dev && cpufreq_dev->cool_dev == cdev)
+                       break;
+               cpufreq_dev_count++;
+       }
+       if (!cpufreq_dev || cpufreq_dev->cool_dev != cdev) {
+               mutex_unlock(&cooling_cpufreq_lock);
+               return;
+       }
+       list_del(&cpufreq_dev->node);
+       /* Unregister the notifier for the last cpufreq cooling device */
+       if (cpufreq_dev_count == 1) {
+               cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
+                                       CPUFREQ_POLICY_NOTIFIER);
+       }
+       mutex_unlock(&cooling_cpufreq_lock);
+       thermal_cooling_device_unregister(cpufreq_dev->cool_dev);
+       release_idr(&cpufreq_idr, cpufreq_dev->id);
+       if (cpufreq_dev_count == 1)
+               mutex_destroy(&cooling_cpufreq_lock);
+       kfree(cpufreq_dev);
+ }
+ EXPORT_SYMBOL(cpufreq_cooling_unregister);
index efd81bb25e0157926ac8a03a556758f2ed124b1a,47498b8719032668f02c08c235614f0e55464ade..9ee42ca4d289754cb99b374a32eb8bdc59371e46
@@@ -41,15 -41,25 +41,25 @@@ MODULE_AUTHOR("Zhang Rui")
  MODULE_DESCRIPTION("Generic thermal management sysfs support");
  MODULE_LICENSE("GPL");
  
- struct thermal_cooling_device_instance {
+ #define THERMAL_NO_TARGET -1UL
+ /*
+  * This structure is used to describe the behavior of
+  * a certain cooling device on a certain trip point
+  * in a certain thermal zone
+  */
+ struct thermal_instance {
        int id;
        char name[THERMAL_NAME_LENGTH];
        struct thermal_zone_device *tz;
        struct thermal_cooling_device *cdev;
        int trip;
+       unsigned long upper;    /* Highest cooling state for this trip point */
+       unsigned long lower;    /* Lowest cooling state for this trip point */
+       unsigned long target;   /* expected cooling state */
        char attr_name[THERMAL_NAME_LENGTH];
        struct device_attribute attr;
-       struct list_head node;
+       struct list_head tz_node; /* node in tz->thermal_instances */
+       struct list_head cdev_node; /* node in cdev->thermal_instances */
  };
  
  static DEFINE_IDR(thermal_tz_idr);
@@@ -78,7 -88,7 +88,7 @@@ again
        else if (unlikely(err))
                return err;
  
 -      *id = *id & MAX_ID_MASK;
 +      *id = *id & MAX_IDR_MASK;
        return 0;
  }
  
@@@ -308,8 -318,9 +318,9 @@@ passive_store(struct device *dev, struc
                        if (!strncmp("Processor", cdev->type,
                                     sizeof("Processor")))
                                thermal_zone_bind_cooling_device(tz,
-                                                                THERMAL_TRIPS_NONE,
-                                                                cdev);
+                                               THERMAL_TRIPS_NONE, cdev,
+                                               THERMAL_NO_LIMIT,
+                                               THERMAL_NO_LIMIT);
                }
                mutex_unlock(&thermal_list_lock);
                if (!tz->passive_delay)
                tz->passive_delay = 0;
        }
  
-       tz->tc1 = 1;
-       tz->tc2 = 1;
        tz->forced_passive = state;
  
        thermal_zone_device_update(tz);
@@@ -425,10 -433,10 +433,10 @@@ static ssize_
  thermal_cooling_device_trip_point_show(struct device *dev,
                                       struct device_attribute *attr, char *buf)
  {
-       struct thermal_cooling_device_instance *instance;
+       struct thermal_instance *instance;
  
        instance =
-           container_of(attr, struct thermal_cooling_device_instance, attr);
+           container_of(attr, struct thermal_instance, attr);
  
        if (instance->trip == THERMAL_TRIPS_NONE)
                return sprintf(buf, "-1\n");
@@@ -590,7 -598,7 +598,7 @@@ thermal_add_hwmon_sysfs(struct thermal_
        temp->tz = tz;
        hwmon->count++;
  
-       snprintf(temp->temp_input.name, THERMAL_NAME_LENGTH,
+       snprintf(temp->temp_input.name, sizeof(temp->temp_input.name),
                 "temp%d_input", hwmon->count);
        temp->temp_input.attr.attr.name = temp->temp_input.name;
        temp->temp_input.attr.attr.mode = 0444;
        if (tz->ops->get_crit_temp) {
                unsigned long temperature;
                if (!tz->ops->get_crit_temp(tz, &temperature)) {
-                       snprintf(temp->temp_crit.name, THERMAL_NAME_LENGTH,
+                       snprintf(temp->temp_crit.name,
+                                sizeof(temp->temp_crit.name),
                                "temp%d_crit", hwmon->count);
                        temp->temp_crit.attr.attr.name = temp->temp_crit.name;
                        temp->temp_crit.attr.attr.mode = 0444;
@@@ -694,84 -703,19 +703,16 @@@ thermal_remove_hwmon_sysfs(struct therm
  static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
                                            int delay)
  {
 -      cancel_delayed_work(&(tz->poll_queue));
 -
 -      if (!delay)
 -              return;
 -
        if (delay > 1000)
 -              queue_delayed_work(system_freezable_wq, &(tz->poll_queue),
 -                                    round_jiffies(msecs_to_jiffies(delay)));
 +              mod_delayed_work(system_freezable_wq, &tz->poll_queue,
 +                               round_jiffies(msecs_to_jiffies(delay)));
 +      else if (delay)
 +              mod_delayed_work(system_freezable_wq, &tz->poll_queue,
 +                               msecs_to_jiffies(delay));
        else
 -              queue_delayed_work(system_freezable_wq, &(tz->poll_queue),
 -                                    msecs_to_jiffies(delay));
 +              cancel_delayed_work(&tz->poll_queue);
  }
  
- static void thermal_zone_device_passive(struct thermal_zone_device *tz,
-                                       int temp, int trip_temp, int trip)
- {
-       int trend = 0;
-       struct thermal_cooling_device_instance *instance;
-       struct thermal_cooling_device *cdev;
-       long state, max_state;
-       /*
-        * Above Trip?
-        * -----------
-        * Calculate the thermal trend (using the passive cooling equation)
-        * and modify the performance limit for all passive cooling devices
-        * accordingly.  Note that we assume symmetry.
-        */
-       if (temp >= trip_temp) {
-               tz->passive = true;
-               trend = (tz->tc1 * (temp - tz->last_temperature)) +
-                       (tz->tc2 * (temp - trip_temp));
-               /* Heating up? */
-               if (trend > 0) {
-                       list_for_each_entry(instance, &tz->cooling_devices,
-                                           node) {
-                               if (instance->trip != trip)
-                                       continue;
-                               cdev = instance->cdev;
-                               cdev->ops->get_cur_state(cdev, &state);
-                               cdev->ops->get_max_state(cdev, &max_state);
-                               if (state++ < max_state)
-                                       cdev->ops->set_cur_state(cdev, state);
-                       }
-               } else if (trend < 0) { /* Cooling off? */
-                       list_for_each_entry(instance, &tz->cooling_devices,
-                                           node) {
-                               if (instance->trip != trip)
-                                       continue;
-                               cdev = instance->cdev;
-                               cdev->ops->get_cur_state(cdev, &state);
-                               cdev->ops->get_max_state(cdev, &max_state);
-                               if (state > 0)
-                                       cdev->ops->set_cur_state(cdev, --state);
-                       }
-               }
-               return;
-       }
-       /*
-        * Below Trip?
-        * -----------
-        * Implement passive cooling hysteresis to slowly increase performance
-        * and avoid thrashing around the passive trip point.  Note that we
-        * assume symmetry.
-        */
-       list_for_each_entry(instance, &tz->cooling_devices, node) {
-               if (instance->trip != trip)
-                       continue;
-               cdev = instance->cdev;
-               cdev->ops->get_cur_state(cdev, &state);
-               cdev->ops->get_max_state(cdev, &max_state);
-               if (state > 0)
-                       cdev->ops->set_cur_state(cdev, --state);
-               if (state == 0)
-                       tz->passive = false;
-       }
- }
  static void thermal_zone_device_check(struct work_struct *work)
  {
        struct thermal_zone_device *tz = container_of(work, struct
   */
  int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
                                     int trip,
-                                    struct thermal_cooling_device *cdev)
+                                    struct thermal_cooling_device *cdev,
+                                    unsigned long upper, unsigned long lower)
  {
-       struct thermal_cooling_device_instance *dev;
-       struct thermal_cooling_device_instance *pos;
+       struct thermal_instance *dev;
+       struct thermal_instance *pos;
        struct thermal_zone_device *pos1;
        struct thermal_cooling_device *pos2;
+       unsigned long max_state;
        int result;
  
        if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
        if (tz != pos1 || cdev != pos2)
                return -EINVAL;
  
+       cdev->ops->get_max_state(cdev, &max_state);
+       /* lower default 0, upper default max_state */
+       lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
+       upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
+       if (lower > upper || upper > max_state)
+               return -EINVAL;
        dev =
-           kzalloc(sizeof(struct thermal_cooling_device_instance), GFP_KERNEL);
+           kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
        if (!dev)
                return -ENOMEM;
        dev->tz = tz;
        dev->cdev = cdev;
        dev->trip = trip;
+       dev->upper = upper;
+       dev->lower = lower;
+       dev->target = THERMAL_NO_TARGET;
        result = get_idr(&tz->idr, &tz->lock, &dev->id);
        if (result)
                goto free_mem;
                goto remove_symbol_link;
  
        mutex_lock(&tz->lock);
-       list_for_each_entry(pos, &tz->cooling_devices, node)
+       mutex_lock(&cdev->lock);
+       list_for_each_entry(pos, &tz->thermal_instances, tz_node)
            if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
                result = -EEXIST;
                break;
        }
-       if (!result)
-               list_add_tail(&dev->node, &tz->cooling_devices);
+       if (!result) {
+               list_add_tail(&dev->tz_node, &tz->thermal_instances);
+               list_add_tail(&dev->cdev_node, &cdev->thermal_instances);
+       }
+       mutex_unlock(&cdev->lock);
        mutex_unlock(&tz->lock);
  
        if (!result)
@@@ -877,16 -840,20 +837,20 @@@ int thermal_zone_unbind_cooling_device(
                                       int trip,
                                       struct thermal_cooling_device *cdev)
  {
-       struct thermal_cooling_device_instance *pos, *next;
+       struct thermal_instance *pos, *next;
  
        mutex_lock(&tz->lock);
-       list_for_each_entry_safe(pos, next, &tz->cooling_devices, node) {
+       mutex_lock(&cdev->lock);
+       list_for_each_entry_safe(pos, next, &tz->thermal_instances, tz_node) {
                if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
-                       list_del(&pos->node);
+                       list_del(&pos->tz_node);
+                       list_del(&pos->cdev_node);
+                       mutex_unlock(&cdev->lock);
                        mutex_unlock(&tz->lock);
                        goto unbind;
                }
        }
+       mutex_unlock(&cdev->lock);
        mutex_unlock(&tz->lock);
  
        return -ENODEV;
@@@ -934,7 -901,7 +898,7 @@@ thermal_cooling_device_register(char *t
        struct thermal_zone_device *pos;
        int result;
  
-       if (strlen(type) >= THERMAL_NAME_LENGTH)
+       if (type && strlen(type) >= THERMAL_NAME_LENGTH)
                return ERR_PTR(-EINVAL);
  
        if (!ops || !ops->get_max_state || !ops->get_cur_state ||
                return ERR_PTR(result);
        }
  
-       strcpy(cdev->type, type);
+       strcpy(cdev->type, type ? : "");
+       mutex_init(&cdev->lock);
+       INIT_LIST_HEAD(&cdev->thermal_instances);
        cdev->ops = ops;
+       cdev->updated = true;
        cdev->device.class = &thermal_class;
        cdev->devdata = devdata;
        dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
@@@ -1044,6 -1014,136 +1011,136 @@@ void thermal_cooling_device_unregister(
  }
  EXPORT_SYMBOL(thermal_cooling_device_unregister);
  
+ static void thermal_cdev_do_update(struct thermal_cooling_device *cdev)
+ {
+       struct thermal_instance *instance;
+       unsigned long target = 0;
+       /* cooling device is updated*/
+       if (cdev->updated)
+               return;
+       mutex_lock(&cdev->lock);
+       /* Make sure cdev enters the deepest cooling state */
+       list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
+               if (instance->target == THERMAL_NO_TARGET)
+                       continue;
+               if (instance->target > target)
+                       target = instance->target;
+       }
+       mutex_unlock(&cdev->lock);
+       cdev->ops->set_cur_state(cdev, target);
+       cdev->updated = true;
+ }
+ static void thermal_zone_do_update(struct thermal_zone_device *tz)
+ {
+       struct thermal_instance *instance;
+       list_for_each_entry(instance, &tz->thermal_instances, tz_node)
+               thermal_cdev_do_update(instance->cdev);
+ }
+ /*
+  * Cooling algorithm for both active and passive cooling
+  *
+  * 1. if the temperature is higher than a trip point,
+  *    a. if the trend is THERMAL_TREND_RAISING, use higher cooling
+  *       state for this trip point
+  *    b. if the trend is THERMAL_TREND_DROPPING, use lower cooling
+  *       state for this trip point
+  *
+  * 2. if the temperature is lower than a trip point, use lower
+  *    cooling state for this trip point
+  *
+  * Note that this behaves the same as the previous passive cooling
+  * algorithm.
+  */
+ static void thermal_zone_trip_update(struct thermal_zone_device *tz,
+                                    int trip, long temp)
+ {
+       struct thermal_instance *instance;
+       struct thermal_cooling_device *cdev = NULL;
+       unsigned long cur_state, max_state;
+       long trip_temp;
+       enum thermal_trip_type trip_type;
+       enum thermal_trend trend;
+       if (trip == THERMAL_TRIPS_NONE) {
+               trip_temp = tz->forced_passive;
+               trip_type = THERMAL_TRIPS_NONE;
+       } else {
+               tz->ops->get_trip_temp(tz, trip, &trip_temp);
+               tz->ops->get_trip_type(tz, trip, &trip_type);
+       }
+       if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
+               /*
+                * compare the current temperature and previous temperature
+                * to get the thermal trend, if no special requirement
+                */
+               if (tz->temperature > tz->last_temperature)
+                       trend = THERMAL_TREND_RAISING;
+               else if (tz->temperature < tz->last_temperature)
+                       trend = THERMAL_TREND_DROPPING;
+               else
+                       trend = THERMAL_TREND_STABLE;
+       }
+       if (temp >= trip_temp) {
+               list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
+                       if (instance->trip != trip)
+                               continue;
+                       cdev = instance->cdev;
+                       cdev->ops->get_cur_state(cdev, &cur_state);
+                       cdev->ops->get_max_state(cdev, &max_state);
+                       if (trend == THERMAL_TREND_RAISING) {
+                               cur_state = cur_state < instance->upper ?
+                                           (cur_state + 1) : instance->upper;
+                       } else if (trend == THERMAL_TREND_DROPPING) {
+                               cur_state = cur_state > instance->lower ?
+                                   (cur_state - 1) : instance->lower;
+                       }
+                       /* activate a passive thermal instance */
+                       if ((trip_type == THERMAL_TRIP_PASSIVE ||
+                            trip_type == THERMAL_TRIPS_NONE) &&
+                            instance->target == THERMAL_NO_TARGET)
+                               tz->passive++;
+                       instance->target = cur_state;
+                       cdev->updated = false; /* cooling device needs update */
+               }
+       } else {        /* below trip */
+               list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
+                       if (instance->trip != trip)
+                               continue;
+                       /* Do not use the inactive thermal instance */
+                       if (instance->target == THERMAL_NO_TARGET)
+                               continue;
+                       cdev = instance->cdev;
+                       cdev->ops->get_cur_state(cdev, &cur_state);
+                       cur_state = cur_state > instance->lower ?
+                                   (cur_state - 1) : THERMAL_NO_TARGET;
+                       /* deactivate a passive thermal instance */
+                       if ((trip_type == THERMAL_TRIP_PASSIVE ||
+                            trip_type == THERMAL_TRIPS_NONE) &&
+                            cur_state == THERMAL_NO_TARGET)
+                               tz->passive--;
+                       instance->target = cur_state;
+                       cdev->updated = false; /* cooling device needs update */
+               }
+       }
+       return;
+ }
  /**
   * thermal_zone_device_update - force an update of a thermal zone's state
   * @ttz:      the thermal zone to update
@@@ -1054,8 -1154,6 +1151,6 @@@ void thermal_zone_device_update(struct 
        int count, ret = 0;
        long temp, trip_temp;
        enum thermal_trip_type trip_type;
-       struct thermal_cooling_device_instance *instance;
-       struct thermal_cooling_device *cdev;
  
        mutex_lock(&tz->lock);
  
                goto leave;
        }
  
+       tz->last_temperature = tz->temperature;
+       tz->temperature = temp;
        for (count = 0; count < tz->trips; count++) {
                tz->ops->get_trip_type(tz, count, &trip_type);
                tz->ops->get_trip_temp(tz, count, &trip_temp);
                                        tz->ops->notify(tz, count, trip_type);
                        break;
                case THERMAL_TRIP_ACTIVE:
-                       list_for_each_entry(instance, &tz->cooling_devices,
-                                           node) {
-                               if (instance->trip != count)
-                                       continue;
-                               cdev = instance->cdev;
-                               if (temp >= trip_temp)
-                                       cdev->ops->set_cur_state(cdev, 1);
-                               else
-                                       cdev->ops->set_cur_state(cdev, 0);
-                       }
+                       thermal_zone_trip_update(tz, count, temp);
                        break;
                case THERMAL_TRIP_PASSIVE:
                        if (temp >= trip_temp || tz->passive)
-                               thermal_zone_device_passive(tz, temp,
-                                                           trip_temp, count);
+                               thermal_zone_trip_update(tz, count, temp);
                        break;
                }
        }
  
        if (tz->forced_passive)
-               thermal_zone_device_passive(tz, temp, tz->forced_passive,
-                                           THERMAL_TRIPS_NONE);
-       tz->last_temperature = temp;
+               thermal_zone_trip_update(tz, THERMAL_TRIPS_NONE, temp);
+       thermal_zone_do_update(tz);
  
  leave:
        if (tz->passive)
@@@ -1236,8 -1323,6 +1320,6 @@@ static void remove_trip_attrs(struct th
   * @mask:     a bit string indicating the writeablility of trip points
   * @devdata:  private device data
   * @ops:      standard thermal zone device callbacks
-  * @tc1:      thermal coefficient 1 for passive calculations
-  * @tc2:      thermal coefficient 2 for passive calculations
   * @passive_delay: number of milliseconds to wait between polls when
   *               performing passive cooling
   * @polling_delay: number of milliseconds to wait between polls when checking
   *               driven systems)
   *
   * thermal_zone_device_unregister() must be called when the device is no
-  * longer needed. The passive cooling formula uses tc1 and tc2 as described in
-  * section 11.1.5.1 of the ACPI specification 3.0.
+  * longer needed. The passive cooling depends on the .get_trend() return value.
   */
  struct thermal_zone_device *thermal_zone_device_register(const char *type,
        int trips, int mask, void *devdata,
        const struct thermal_zone_device_ops *ops,
-       int tc1, int tc2, int passive_delay, int polling_delay)
+       int passive_delay, int polling_delay)
  {
        struct thermal_zone_device *tz;
        struct thermal_cooling_device *pos;
        int count;
        int passive = 0;
  
-       if (strlen(type) >= THERMAL_NAME_LENGTH)
+       if (type && strlen(type) >= THERMAL_NAME_LENGTH)
                return ERR_PTR(-EINVAL);
  
        if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
        if (!tz)
                return ERR_PTR(-ENOMEM);
  
-       INIT_LIST_HEAD(&tz->cooling_devices);
+       INIT_LIST_HEAD(&tz->thermal_instances);
        idr_init(&tz->idr);
        mutex_init(&tz->lock);
        result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
                return ERR_PTR(result);
        }
  
-       strcpy(tz->type, type);
+       strcpy(tz->type, type ? : "");
        tz->ops = ops;
        tz->device.class = &thermal_class;
        tz->devdata = devdata;
        tz->trips = trips;
-       tz->tc1 = tc1;
-       tz->tc2 = tc2;
        tz->passive_delay = passive_delay;
        tz->polling_delay = polling_delay;