Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 1 Mar 2013 03:48:26 +0000 (19:48 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 1 Mar 2013 03:48:26 +0000 (19:48 -0800)
Pull thermal management updates from Zhang Rui:
 "Highlights:

   - introduction of Dove thermal sensor driver.

   - introduction of Kirkwood thermal sensor driver.

   - introduction of intel_powerclamp thermal cooling device driver.

   - add interrupt and DT support for rcar thermal driver.

   - add thermal emulation support which allows platform thermal driver
     to do software/hardware emulation for thermal issues."

* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux: (36 commits)
  thermal: rcar: remove __devinitconst
  thermal: return an error on failure to register thermal class
  Thermal: rename thermal governor Kconfig option to avoid generic naming
  thermal: exynos: Use the new thermal trend type for quick cooling action.
  Thermal: exynos: Add support for temperature falling interrupt.
  Thermal: Dove: Add Themal sensor support for Dove.
  thermal: Add support for the thermal sensor on Kirkwood SoCs
  thermal: rcar: add Device Tree support
  thermal: rcar: remove machine_power_off() from rcar_thermal_notify()
  thermal: rcar: add interrupt support
  thermal: rcar: add read/write functions for common/priv data
  thermal: rcar: multi channel support
  thermal: rcar: use mutex lock instead of spin lock
  thermal: rcar: enable CPCTL to use hardware TSC deciding
  thermal: rcar: use parenthesis on macro
  Thermal: fix a build warning when CONFIG_THERMAL_EMULATION cleared
  Thermal: fix a wrong comment
  thermal: sysfs: Add a new sysfs node emul_temp for thermal emulation
  PM: intel_powerclamp: off by one in start_power_clamp()
  thermal: exynos: Miscellaneous fixes to support falling threshold interrupt
  ...

1  2 
drivers/thermal/cpu_cooling.c
drivers/thermal/exynos_thermal.c
drivers/thermal/thermal_sys.c
kernel/time/tick-sched.c

@@@ -73,14 -73,21 +73,14 @@@ static struct cpufreq_cooling_device *n
   */
  static int get_idr(struct idr *idr, int *id)
  {
 -      int err;
 -again:
 -      if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
 -              return -ENOMEM;
 +      int ret;
  
        mutex_lock(&cooling_cpufreq_lock);
 -      err = idr_get_new(idr, NULL, id);
 +      ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
        mutex_unlock(&cooling_cpufreq_lock);
 -
 -      if (unlikely(err == -EAGAIN))
 -              goto again;
 -      else if (unlikely(err))
 -              return err;
 -
 -      *id = *id & MAX_IDR_MASK;
 +      if (unlikely(ret < 0))
 +              return ret;
 +      *id = ret;
        return 0;
  }
  
@@@ -111,8 -118,8 +111,8 @@@ static int is_cpufreq_valid(int 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
+  * @level: level of frequency, equals cooling state of cpu cooling device
+  *    e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc
   */
  static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level)
  {
@@@ -82,7 -82,7 +82,7 @@@
  
  #define EXYNOS_TRIMINFO_RELOAD                0x1
  #define EXYNOS_TMU_CLEAR_RISE_INT     0x111
- #define EXYNOS_TMU_CLEAR_FALL_INT     (0x111 << 16)
+ #define EXYNOS_TMU_CLEAR_FALL_INT     (0x111 << 12)
  #define EXYNOS_MUX_ADDR_VALUE         6
  #define EXYNOS_MUX_ADDR_SHIFT         20
  #define EXYNOS_TMU_TRIP_MODE_SHIFT    13
  #define SENSOR_NAME_LEN       16
  #define MAX_TRIP_COUNT        8
  #define MAX_COOLING_DEVICE 4
+ #define MAX_THRESHOLD_LEVS 4
  
  #define ACTIVE_INTERVAL 500
  #define IDLE_INTERVAL 10000
  #define MCELSIUS      1000
  
+ #ifdef CONFIG_EXYNOS_THERMAL_EMUL
+ #define EXYNOS_EMUL_TIME      0x57F0
+ #define EXYNOS_EMUL_TIME_SHIFT        16
+ #define EXYNOS_EMUL_DATA_SHIFT        8
+ #define EXYNOS_EMUL_DATA_MASK 0xFF
+ #define EXYNOS_EMUL_ENABLE    0x1
+ #endif /* CONFIG_EXYNOS_THERMAL_EMUL */
  /* CPU Zone information */
  #define PANIC_ZONE      4
  #define WARN_ZONE       3
@@@ -125,6 -134,7 +134,7 @@@ struct exynos_tmu_data 
  struct        thermal_trip_point_conf {
        int trip_val[MAX_TRIP_COUNT];
        int trip_count;
+       u8 trigger_falling;
  };
  
  struct        thermal_cooling_conf {
@@@ -174,7 -184,8 +184,8 @@@ static int exynos_set_mode(struct therm
  
        mutex_lock(&th_zone->therm_dev->lock);
  
-       if (mode == THERMAL_DEVICE_ENABLED)
+       if (mode == THERMAL_DEVICE_ENABLED &&
+               !th_zone->sensor_conf->trip_data.trigger_falling)
                th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
        else
                th_zone->therm_dev->polling_delay = 0;
@@@ -284,7 -295,7 +295,7 @@@ static int exynos_bind(struct thermal_z
                case MONITOR_ZONE:
                case WARN_ZONE:
                        if (thermal_zone_bind_cooling_device(thermal, i, cdev,
-                                                               level, level)) {
+                                                               level, 0)) {
                                pr_err("error binding cdev inst %d\n", i);
                                ret = -EINVAL;
                        }
@@@ -362,10 -373,17 +373,17 @@@ static int exynos_get_temp(struct therm
  static int exynos_get_trend(struct thermal_zone_device *thermal,
                        int trip, enum thermal_trend *trend)
  {
-       if (thermal->temperature >= trip)
-               *trend = THERMAL_TREND_RAISING;
+       int ret;
+       unsigned long trip_temp;
+       ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
+       if (ret < 0)
+               return ret;
+       if (thermal->temperature >= trip_temp)
+               *trend = THERMAL_TREND_RAISE_FULL;
        else
-               *trend = THERMAL_TREND_DROPPING;
+               *trend = THERMAL_TREND_DROP_FULL;
  
        return 0;
  }
@@@ -413,7 -431,8 +431,8 @@@ static void exynos_report_trigger(void
                        break;
        }
  
-       if (th_zone->mode == THERMAL_DEVICE_ENABLED) {
+       if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
+               !th_zone->sensor_conf->trip_data.trigger_falling) {
                if (i > 0)
                        th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
                else
@@@ -452,7 -471,8 +471,8 @@@ static int exynos_register_thermal(stru
  
        th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
                        EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
-                       IDLE_INTERVAL);
+                       sensor_conf->trip_data.trigger_falling ?
+                       0 : IDLE_INTERVAL);
  
        if (IS_ERR(th_zone->therm_dev)) {
                pr_err("Failed to register thermal zone device\n");
@@@ -559,8 -579,9 +579,9 @@@ static int exynos_tmu_initialize(struc
  {
        struct exynos_tmu_data *data = platform_get_drvdata(pdev);
        struct exynos_tmu_platform_data *pdata = data->pdata;
-       unsigned int status, trim_info, rising_threshold;
-       int ret = 0, threshold_code;
+       unsigned int status, trim_info;
+       unsigned int rising_threshold = 0, falling_threshold = 0;
+       int ret = 0, threshold_code, i, trigger_levs = 0;
  
        mutex_lock(&data->lock);
        clk_enable(data->clk);
                        (data->temp_error2 != 0))
                data->temp_error1 = pdata->efuse_value;
  
+       /* Count trigger levels to be enabled */
+       for (i = 0; i < MAX_THRESHOLD_LEVS; i++)
+               if (pdata->trigger_levels[i])
+                       trigger_levs++;
        if (data->soc == SOC_ARCH_EXYNOS4210) {
                /* Write temperature code for threshold */
                threshold_code = temp_to_code(data, pdata->threshold);
                }
                writeb(threshold_code,
                        data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP);
-               writeb(pdata->trigger_levels[0],
-                       data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0);
-               writeb(pdata->trigger_levels[1],
-                       data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL1);
-               writeb(pdata->trigger_levels[2],
-                       data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL2);
-               writeb(pdata->trigger_levels[3],
-                       data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL3);
+               for (i = 0; i < trigger_levs; i++)
+                       writeb(pdata->trigger_levels[i],
+                       data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i * 4);
  
                writel(EXYNOS4210_TMU_INTCLEAR_VAL,
                        data->base + EXYNOS_TMU_REG_INTCLEAR);
        } else if (data->soc == SOC_ARCH_EXYNOS) {
-               /* Write temperature code for threshold */
-               threshold_code = temp_to_code(data, pdata->trigger_levels[0]);
-               if (threshold_code < 0) {
-                       ret = threshold_code;
-                       goto out;
-               }
-               rising_threshold = threshold_code;
-               threshold_code = temp_to_code(data, pdata->trigger_levels[1]);
-               if (threshold_code < 0) {
-                       ret = threshold_code;
-                       goto out;
-               }
-               rising_threshold |= (threshold_code << 8);
-               threshold_code = temp_to_code(data, pdata->trigger_levels[2]);
-               if (threshold_code < 0) {
-                       ret = threshold_code;
-                       goto out;
+               /* Write temperature code for rising and falling threshold */
+               for (i = 0; i < trigger_levs; i++) {
+                       threshold_code = temp_to_code(data,
+                                               pdata->trigger_levels[i]);
+                       if (threshold_code < 0) {
+                               ret = threshold_code;
+                               goto out;
+                       }
+                       rising_threshold |= threshold_code << 8 * i;
+                       if (pdata->threshold_falling) {
+                               threshold_code = temp_to_code(data,
+                                               pdata->trigger_levels[i] -
+                                               pdata->threshold_falling);
+                               if (threshold_code > 0)
+                                       falling_threshold |=
+                                               threshold_code << 8 * i;
+                       }
                }
-               rising_threshold |= (threshold_code << 16);
  
                writel(rising_threshold,
                                data->base + EXYNOS_THD_TEMP_RISE);
-               writel(0, data->base + EXYNOS_THD_TEMP_FALL);
+               writel(falling_threshold,
+                               data->base + EXYNOS_THD_TEMP_FALL);
  
-               writel(EXYNOS_TMU_CLEAR_RISE_INT|EXYNOS_TMU_CLEAR_FALL_INT,
+               writel(EXYNOS_TMU_CLEAR_RISE_INT | EXYNOS_TMU_CLEAR_FALL_INT,
                                data->base + EXYNOS_TMU_REG_INTCLEAR);
        }
  out:
@@@ -664,6 -684,8 +684,8 @@@ static void exynos_tmu_control(struct p
                        pdata->trigger_level2_en << 8 |
                        pdata->trigger_level1_en << 4 |
                        pdata->trigger_level0_en;
+               if (pdata->threshold_falling)
+                       interrupt_en |= interrupt_en << 16;
        } else {
                con |= EXYNOS_TMU_CORE_OFF;
                interrupt_en = 0; /* Disable all interrupts */
@@@ -697,20 -719,19 +719,19 @@@ static void exynos_tmu_work(struct work
        struct exynos_tmu_data *data = container_of(work,
                        struct exynos_tmu_data, irq_work);
  
+       exynos_report_trigger();
        mutex_lock(&data->lock);
        clk_enable(data->clk);
        if (data->soc == SOC_ARCH_EXYNOS)
-               writel(EXYNOS_TMU_CLEAR_RISE_INT,
+               writel(EXYNOS_TMU_CLEAR_RISE_INT |
+                               EXYNOS_TMU_CLEAR_FALL_INT,
                                data->base + EXYNOS_TMU_REG_INTCLEAR);
        else
                writel(EXYNOS4210_TMU_INTCLEAR_VAL,
                                data->base + EXYNOS_TMU_REG_INTCLEAR);
        clk_disable(data->clk);
        mutex_unlock(&data->lock);
-       exynos_report_trigger();
        enable_irq(data->irq);
  }
  
@@@ -759,6 -780,7 +780,7 @@@ static struct exynos_tmu_platform_data 
  
  #if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412)
  static struct exynos_tmu_platform_data const exynos_default_tmu_data = {
+       .threshold_falling = 10,
        .trigger_levels[0] = 85,
        .trigger_levels[1] = 103,
        .trigger_levels[2] = 110,
@@@ -800,8 -822,6 +822,6 @@@ static const struct of_device_id exynos
        {},
  };
  MODULE_DEVICE_TABLE(of, exynos_tmu_match);
- #else
- #define  exynos_tmu_match NULL
  #endif
  
  static struct platform_device_id exynos_tmu_driver_ids[] = {
@@@ -832,7 -852,95 +852,95 @@@ static inline struct  exynos_tmu_platfo
        return (struct exynos_tmu_platform_data *)
                        platform_get_device_id(pdev)->driver_data;
  }
 -static int __devinit exynos_tmu_probe(struct platform_device *pdev)
+ #ifdef CONFIG_EXYNOS_THERMAL_EMUL
+ static ssize_t exynos_tmu_emulation_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+ {
+       struct platform_device *pdev = container_of(dev,
+                                       struct platform_device, dev);
+       struct exynos_tmu_data *data = platform_get_drvdata(pdev);
+       unsigned int reg;
+       u8 temp_code;
+       int temp = 0;
+       if (data->soc == SOC_ARCH_EXYNOS4210)
+               goto out;
+       mutex_lock(&data->lock);
+       clk_enable(data->clk);
+       reg = readl(data->base + EXYNOS_EMUL_CON);
+       clk_disable(data->clk);
+       mutex_unlock(&data->lock);
+       if (reg & EXYNOS_EMUL_ENABLE) {
+               reg >>= EXYNOS_EMUL_DATA_SHIFT;
+               temp_code = reg & EXYNOS_EMUL_DATA_MASK;
+               temp = code_to_temp(data, temp_code);
+       }
+ out:
+       return sprintf(buf, "%d\n", temp * MCELSIUS);
+ }
+ static ssize_t exynos_tmu_emulation_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+ {
+       struct platform_device *pdev = container_of(dev,
+                                       struct platform_device, dev);
+       struct exynos_tmu_data *data = platform_get_drvdata(pdev);
+       unsigned int reg;
+       int temp;
+       if (data->soc == SOC_ARCH_EXYNOS4210)
+               goto out;
+       if (!sscanf(buf, "%d\n", &temp) || temp < 0)
+               return -EINVAL;
+       mutex_lock(&data->lock);
+       clk_enable(data->clk);
+       reg = readl(data->base + EXYNOS_EMUL_CON);
+       if (temp) {
+               /* Both CELSIUS and MCELSIUS type are available for input */
+               if (temp > MCELSIUS)
+                       temp /= MCELSIUS;
+               reg = (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT) |
+                       (temp_to_code(data, (temp / MCELSIUS))
+                        << EXYNOS_EMUL_DATA_SHIFT) | EXYNOS_EMUL_ENABLE;
+       } else {
+               reg &= ~EXYNOS_EMUL_ENABLE;
+       }
+       writel(reg, data->base + EXYNOS_EMUL_CON);
+       clk_disable(data->clk);
+       mutex_unlock(&data->lock);
+ out:
+       return count;
+ }
+ static DEVICE_ATTR(emulation, 0644, exynos_tmu_emulation_show,
+                                       exynos_tmu_emulation_store);
+ static int create_emulation_sysfs(struct device *dev)
+ {
+       return device_create_file(dev, &dev_attr_emulation);
+ }
+ static void remove_emulation_sysfs(struct device *dev)
+ {
+       device_remove_file(dev, &dev_attr_emulation);
+ }
+ #else
+ static inline int create_emulation_sysfs(struct device *dev) { return 0; }
+ static inline void remove_emulation_sysfs(struct device *dev) {}
+ #endif
 +static int exynos_tmu_probe(struct platform_device *pdev)
  {
        struct exynos_tmu_data *data;
        struct exynos_tmu_platform_data *pdata = pdev->dev.platform_data;
                return -ENOENT;
        }
  
 -      data->base = devm_request_and_ioremap(&pdev->dev, data->mem);
 -      if (!data->base) {
 -              dev_err(&pdev->dev, "Failed to ioremap memory\n");
 -              return -ENODEV;
 -      }
 +      data->base = devm_ioremap_resource(&pdev->dev, data->mem);
 +      if (IS_ERR(data->base))
 +              return PTR_ERR(data->base);
  
        ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq,
                IRQF_TRIGGER_RISING, "exynos-tmu", data);
                exynos_sensor_conf.trip_data.trip_val[i] =
                        pdata->threshold + pdata->trigger_levels[i];
  
+       exynos_sensor_conf.trip_data.trigger_falling = pdata->threshold_falling;
        exynos_sensor_conf.cooling_data.freq_clip_count =
                                                pdata->freq_tab_count;
        for (i = 0; i < pdata->freq_tab_count; i++) {
                dev_err(&pdev->dev, "Failed to register thermal interface\n");
                goto err_clk;
        }
+       ret = create_emulation_sysfs(&pdev->dev);
+       if (ret)
+               dev_err(&pdev->dev, "Failed to create emulation mode sysfs node\n");
        return 0;
  err_clk:
        platform_set_drvdata(pdev, NULL);
        return ret;
  }
  
 -static int __devexit exynos_tmu_remove(struct platform_device *pdev)
 +static int exynos_tmu_remove(struct platform_device *pdev)
  {
        struct exynos_tmu_data *data = platform_get_drvdata(pdev);
  
+       remove_emulation_sysfs(&pdev->dev);
        exynos_tmu_control(pdev, false);
  
        exynos_unregister_thermal();
@@@ -980,10 -1099,10 +1097,10 @@@ static struct platform_driver exynos_tm
                .name   = "exynos-tmu",
                .owner  = THIS_MODULE,
                .pm     = EXYNOS_TMU_PM,
-               .of_match_table = exynos_tmu_match,
+               .of_match_table = of_match_ptr(exynos_tmu_match),
        },
        .probe = exynos_tmu_probe,
 -      .remove = __devexit_p(exynos_tmu_remove),
 +      .remove = exynos_tmu_remove,
        .id_table = exynos_tmu_driver_ids,
  };
  
@@@ -32,7 -32,6 +32,6 @@@
  #include <linux/kdev_t.h>
  #include <linux/idr.h>
  #include <linux/thermal.h>
- #include <linux/spinlock.h>
  #include <linux/reboot.h>
  #include <net/netlink.h>
  #include <net/genetlink.h>
@@@ -132,16 -131,23 +131,16 @@@ EXPORT_SYMBOL_GPL(thermal_unregister_go
  
  static int get_idr(struct idr *idr, struct mutex *lock, int *id)
  {
 -      int err;
 -
 -again:
 -      if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
 -              return -ENOMEM;
 +      int ret;
  
        if (lock)
                mutex_lock(lock);
 -      err = idr_get_new(idr, NULL, id);
 +      ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
        if (lock)
                mutex_unlock(lock);
 -      if (unlikely(err == -EAGAIN))
 -              goto again;
 -      else if (unlikely(err))
 -              return err;
 -
 -      *id = *id & MAX_IDR_MASK;
 +      if (unlikely(ret < 0))
 +              return ret;
 +      *id = ret;
        return 0;
  }
  
@@@ -348,8 -354,9 +347,9 @@@ static void handle_critical_trips(struc
                tz->ops->notify(tz, trip, trip_type);
  
        if (trip_type == THERMAL_TRIP_CRITICAL) {
-               pr_emerg("Critical temperature reached(%d C),shutting down\n",
-                        tz->temperature / 1000);
+               dev_emerg(&tz->device,
+                         "critical temperature reached(%d C),shutting down\n",
+                         tz->temperature / 1000);
                orderly_poweroff(true);
        }
  }
@@@ -371,23 -378,57 +371,57 @@@ static void handle_thermal_trip(struct 
        monitor_thermal_zone(tz);
  }
  
+ static int thermal_zone_get_temp(struct thermal_zone_device *tz,
+                               unsigned long *temp)
+ {
+       int ret = 0;
+ #ifdef CONFIG_THERMAL_EMULATION
+       int count;
+       unsigned long crit_temp = -1UL;
+       enum thermal_trip_type type;
+ #endif
+       mutex_lock(&tz->lock);
+       ret = tz->ops->get_temp(tz, temp);
+ #ifdef CONFIG_THERMAL_EMULATION
+       if (!tz->emul_temperature)
+               goto skip_emul;
+       for (count = 0; count < tz->trips; count++) {
+               ret = tz->ops->get_trip_type(tz, count, &type);
+               if (!ret && type == THERMAL_TRIP_CRITICAL) {
+                       ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
+                       break;
+               }
+       }
+       if (ret)
+               goto skip_emul;
+       if (*temp < crit_temp)
+               *temp = tz->emul_temperature;
+ skip_emul:
+ #endif
+       mutex_unlock(&tz->lock);
+       return ret;
+ }
  static void update_temperature(struct thermal_zone_device *tz)
  {
        long temp;
        int ret;
  
-       mutex_lock(&tz->lock);
-       ret = tz->ops->get_temp(tz, &temp);
+       ret = thermal_zone_get_temp(tz, &temp);
        if (ret) {
-               pr_warn("failed to read out thermal zone %d\n", tz->id);
-               goto exit;
+               dev_warn(&tz->device, "failed to read out thermal zone %d\n",
+                        tz->id);
+               return;
        }
  
+       mutex_lock(&tz->lock);
        tz->last_temperature = tz->temperature;
        tz->temperature = temp;
- exit:
        mutex_unlock(&tz->lock);
  }
  
@@@ -430,10 -471,7 +464,7 @@@ temp_show(struct device *dev, struct de
        long temperature;
        int ret;
  
-       if (!tz->ops->get_temp)
-               return -EPERM;
-       ret = tz->ops->get_temp(tz, &temperature);
+       ret = thermal_zone_get_temp(tz, &temperature);
  
        if (ret)
                return ret;
@@@ -693,6 -731,31 +724,31 @@@ policy_show(struct device *dev, struct 
        return sprintf(buf, "%s\n", tz->governor->name);
  }
  
+ #ifdef CONFIG_THERMAL_EMULATION
+ static ssize_t
+ emul_temp_store(struct device *dev, struct device_attribute *attr,
+                    const char *buf, size_t count)
+ {
+       struct thermal_zone_device *tz = to_thermal_zone(dev);
+       int ret = 0;
+       unsigned long temperature;
+       if (kstrtoul(buf, 10, &temperature))
+               return -EINVAL;
+       if (!tz->ops->set_emul_temp) {
+               mutex_lock(&tz->lock);
+               tz->emul_temperature = temperature;
+               mutex_unlock(&tz->lock);
+       } else {
+               ret = tz->ops->set_emul_temp(tz, temperature);
+       }
+       return ret ? ret : count;
+ }
+ static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
+ #endif/*CONFIG_THERMAL_EMULATION*/
  static DEVICE_ATTR(type, 0444, type_show, NULL);
  static DEVICE_ATTR(temp, 0444, temp_show, NULL);
  static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
@@@ -835,7 -898,7 +891,7 @@@ temp_input_show(struct device *dev, str
                                       temp_input);
        struct thermal_zone_device *tz = temp->tz;
  
-       ret = tz->ops->get_temp(tz, &temperature);
+       ret = thermal_zone_get_temp(tz, &temperature);
  
        if (ret)
                return ret;
@@@ -1522,6 -1585,9 +1578,9 @@@ struct thermal_zone_device *thermal_zon
        if (!ops || !ops->get_temp)
                return ERR_PTR(-EINVAL);
  
+       if (trips > 0 && !ops->get_trip_type)
+               return ERR_PTR(-EINVAL);
        tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
        if (!tz)
                return ERR_PTR(-ENOMEM);
                        goto unregister;
        }
  
+ #ifdef CONFIG_THERMAL_EMULATION
+       result = device_create_file(&tz->device, &dev_attr_emul_temp);
+       if (result)
+               goto unregister;
+ #endif
        /* Create policy attribute */
        result = device_create_file(&tz->device, &dev_attr_policy);
        if (result)
@@@ -1704,7 -1775,8 +1768,8 @@@ static struct genl_multicast_group ther
        .name = THERMAL_GENL_MCAST_GROUP_NAME,
  };
  
- int thermal_generate_netlink_event(u32 orig, enum events event)
+ int thermal_generate_netlink_event(struct thermal_zone_device *tz,
+                                       enum events event)
  {
        struct sk_buff *skb;
        struct nlattr *attr;
        int result;
        static unsigned int thermal_event_seqnum;
  
+       if (!tz)
+               return -EINVAL;
        /* allocate memory */
        size = nla_total_size(sizeof(struct thermal_genl_event)) +
               nla_total_size(0);
  
        memset(thermal_event, 0, sizeof(struct thermal_genl_event));
  
-       thermal_event->orig = orig;
+       thermal_event->orig = tz->id;
        thermal_event->event = event;
  
        /* send multicast genetlink message */
  
        result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
        if (result)
-               pr_info("failed to send netlink event:%d\n", result);
+               dev_err(&tz->device, "Failed to send netlink event:%d", result);
  
        return result;
  }
@@@ -1800,6 -1875,7 +1868,7 @@@ static int __init thermal_init(void
                idr_destroy(&thermal_cdev_idr);
                mutex_destroy(&thermal_idr_lock);
                mutex_destroy(&thermal_list_lock);
+               return result;
        }
        result = genetlink_init();
        return result;
diff --combined kernel/time/tick-sched.c
@@@ -20,7 -20,6 +20,7 @@@
  #include <linux/profile.h>
  #include <linux/sched.h>
  #include <linux/module.h>
 +#include <linux/irq_work.h>
  
  #include <asm/irq_regs.h>
  
@@@ -29,7 -28,7 +29,7 @@@
  /*
   * Per cpu nohz control structure
   */
 -static DEFINE_PER_CPU(struct tick_sched, tick_cpu_sched);
 +DEFINE_PER_CPU(struct tick_sched, tick_cpu_sched);
  
  /*
   * The time, when the last jiffy update happened. Protected by jiffies_lock.
@@@ -332,8 -331,8 +332,8 @@@ static ktime_t tick_nohz_stop_sched_tic
                time_delta = timekeeping_max_deferment();
        } while (read_seqretry(&jiffies_lock, seq));
  
 -      if (rcu_needs_cpu(cpu, &rcu_delta_jiffies) || printk_needs_cpu(cpu) ||
 -          arch_needs_cpu(cpu)) {
 +      if (rcu_needs_cpu(cpu, &rcu_delta_jiffies) ||
 +          arch_needs_cpu(cpu) || irq_work_needs_cpu()) {
                next_jiffies = last_jiffies + 1;
                delta_jiffies = 1;
        } else {
@@@ -554,6 -553,7 +554,7 @@@ void tick_nohz_idle_enter(void
  
        local_irq_enable();
  }
+ EXPORT_SYMBOL_GPL(tick_nohz_idle_enter);
  
  /**
   * tick_nohz_irq_exit - update next tick event from interrupt exit
@@@ -632,11 -632,8 +633,11 @@@ static void tick_nohz_restart_sched_tic
  
  static void tick_nohz_account_idle_ticks(struct tick_sched *ts)
  {
 -#ifndef CONFIG_VIRT_CPU_ACCOUNTING
 +#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
        unsigned long ticks;
 +
 +      if (vtime_accounting_enabled())
 +              return;
        /*
         * We stopped the tick in idle. Update process times would miss the
         * time we slept as update_process_times does only a 1 tick
@@@ -685,6 -682,7 +686,7 @@@ void tick_nohz_idle_exit(void
  
        local_irq_enable();
  }
+ EXPORT_SYMBOL_GPL(tick_nohz_idle_exit);
  
  static int tick_nohz_reprogram(struct tick_sched *ts, ktime_t now)
  {