bbc_envctrl.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. /* bbc_envctrl.c: UltraSPARC-III environment control driver.
  2. *
  3. * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
  4. */
  5. #include <linux/kthread.h>
  6. #include <linux/delay.h>
  7. #include <linux/kmod.h>
  8. #include <linux/reboot.h>
  9. #include <linux/of.h>
  10. #include <linux/slab.h>
  11. #include <linux/of_device.h>
  12. #include <asm/oplib.h>
  13. #include "bbc_i2c.h"
  14. #include "max1617.h"
  15. #undef ENVCTRL_TRACE
  16. /* WARNING: Making changes to this driver is very dangerous.
  17. * If you misprogram the sensor chips they can
  18. * cut the power on you instantly.
  19. */
  20. /* Two temperature sensors exist in the SunBLADE-1000 enclosure.
  21. * Both are implemented using max1617 i2c devices. Each max1617
  22. * monitors 2 temperatures, one for one of the cpu dies and the other
  23. * for the ambient temperature.
  24. *
  25. * The max1617 is capable of being programmed with power-off
  26. * temperature values, one low limit and one high limit. These
  27. * can be controlled independently for the cpu or ambient temperature.
  28. * If a limit is violated, the power is simply shut off. The frequency
  29. * with which the max1617 does temperature sampling can be controlled
  30. * as well.
  31. *
  32. * Three fans exist inside the machine, all three are controlled with
  33. * an i2c digital to analog converter. There is a fan directed at the
  34. * two processor slots, another for the rest of the enclosure, and the
  35. * third is for the power supply. The first two fans may be speed
  36. * controlled by changing the voltage fed to them. The third fan may
  37. * only be completely off or on. The third fan is meant to only be
  38. * disabled/enabled when entering/exiting the lowest power-saving
  39. * mode of the machine.
  40. *
  41. * An environmental control kernel thread periodically monitors all
  42. * temperature sensors. Based upon the samples it will adjust the
  43. * fan speeds to try and keep the system within a certain temperature
  44. * range (the goal being to make the fans as quiet as possible without
  45. * allowing the system to get too hot).
  46. *
  47. * If the temperature begins to rise/fall outside of the acceptable
  48. * operating range, a periodic warning will be sent to the kernel log.
  49. * The fans will be put on full blast to attempt to deal with this
  50. * situation. After exceeding the acceptable operating range by a
  51. * certain threshold, the kernel thread will shut down the system.
  52. * Here, the thread is attempting to shut the machine down cleanly
  53. * before the hardware based power-off event is triggered.
  54. */
  55. /* These settings are in Celsius. We use these defaults only
  56. * if we cannot interrogate the cpu-fru SEEPROM.
  57. */
  58. struct temp_limits {
  59. s8 high_pwroff, high_shutdown, high_warn;
  60. s8 low_warn, low_shutdown, low_pwroff;
  61. };
  62. static struct temp_limits cpu_temp_limits[2] = {
  63. { 100, 85, 80, 5, -5, -10 },
  64. { 100, 85, 80, 5, -5, -10 },
  65. };
  66. static struct temp_limits amb_temp_limits[2] = {
  67. { 65, 55, 40, 5, -5, -10 },
  68. { 65, 55, 40, 5, -5, -10 },
  69. };
  70. static LIST_HEAD(all_temps);
  71. static LIST_HEAD(all_fans);
  72. #define CPU_FAN_REG 0xf0
  73. #define SYS_FAN_REG 0xf2
  74. #define PSUPPLY_FAN_REG 0xf4
  75. #define FAN_SPEED_MIN 0x0c
  76. #define FAN_SPEED_MAX 0x3f
  77. #define PSUPPLY_FAN_ON 0x1f
  78. #define PSUPPLY_FAN_OFF 0x00
  79. static void set_fan_speeds(struct bbc_fan_control *fp)
  80. {
  81. /* Put temperatures into range so we don't mis-program
  82. * the hardware.
  83. */
  84. if (fp->cpu_fan_speed < FAN_SPEED_MIN)
  85. fp->cpu_fan_speed = FAN_SPEED_MIN;
  86. if (fp->cpu_fan_speed > FAN_SPEED_MAX)
  87. fp->cpu_fan_speed = FAN_SPEED_MAX;
  88. if (fp->system_fan_speed < FAN_SPEED_MIN)
  89. fp->system_fan_speed = FAN_SPEED_MIN;
  90. if (fp->system_fan_speed > FAN_SPEED_MAX)
  91. fp->system_fan_speed = FAN_SPEED_MAX;
  92. #ifdef ENVCTRL_TRACE
  93. printk("fan%d: Changed fan speed to cpu(%02x) sys(%02x)\n",
  94. fp->index,
  95. fp->cpu_fan_speed, fp->system_fan_speed);
  96. #endif
  97. bbc_i2c_writeb(fp->client, fp->cpu_fan_speed, CPU_FAN_REG);
  98. bbc_i2c_writeb(fp->client, fp->system_fan_speed, SYS_FAN_REG);
  99. bbc_i2c_writeb(fp->client,
  100. (fp->psupply_fan_on ?
  101. PSUPPLY_FAN_ON : PSUPPLY_FAN_OFF),
  102. PSUPPLY_FAN_REG);
  103. }
  104. static void get_current_temps(struct bbc_cpu_temperature *tp)
  105. {
  106. tp->prev_amb_temp = tp->curr_amb_temp;
  107. bbc_i2c_readb(tp->client,
  108. (unsigned char *) &tp->curr_amb_temp,
  109. MAX1617_AMB_TEMP);
  110. tp->prev_cpu_temp = tp->curr_cpu_temp;
  111. bbc_i2c_readb(tp->client,
  112. (unsigned char *) &tp->curr_cpu_temp,
  113. MAX1617_CPU_TEMP);
  114. #ifdef ENVCTRL_TRACE
  115. printk("temp%d: cpu(%d C) amb(%d C)\n",
  116. tp->index,
  117. (int) tp->curr_cpu_temp, (int) tp->curr_amb_temp);
  118. #endif
  119. }
  120. static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp)
  121. {
  122. static int shutting_down = 0;
  123. char *type = "???";
  124. s8 val = -1;
  125. if (shutting_down != 0)
  126. return;
  127. if (tp->curr_amb_temp >= amb_temp_limits[tp->index].high_shutdown ||
  128. tp->curr_amb_temp < amb_temp_limits[tp->index].low_shutdown) {
  129. type = "ambient";
  130. val = tp->curr_amb_temp;
  131. } else if (tp->curr_cpu_temp >= cpu_temp_limits[tp->index].high_shutdown ||
  132. tp->curr_cpu_temp < cpu_temp_limits[tp->index].low_shutdown) {
  133. type = "CPU";
  134. val = tp->curr_cpu_temp;
  135. }
  136. printk(KERN_CRIT "temp%d: Outside of safe %s "
  137. "operating temperature, %d C.\n",
  138. tp->index, type, val);
  139. printk(KERN_CRIT "kenvctrld: Shutting down the system now.\n");
  140. shutting_down = 1;
  141. if (orderly_poweroff(true) < 0)
  142. printk(KERN_CRIT "envctrl: shutdown execution failed\n");
  143. }
  144. #define WARN_INTERVAL (30 * HZ)
  145. static void analyze_ambient_temp(struct bbc_cpu_temperature *tp, unsigned long *last_warn, int tick)
  146. {
  147. int ret = 0;
  148. if (time_after(jiffies, (*last_warn + WARN_INTERVAL))) {
  149. if (tp->curr_amb_temp >=
  150. amb_temp_limits[tp->index].high_warn) {
  151. printk(KERN_WARNING "temp%d: "
  152. "Above safe ambient operating temperature, %d C.\n",
  153. tp->index, (int) tp->curr_amb_temp);
  154. ret = 1;
  155. } else if (tp->curr_amb_temp <
  156. amb_temp_limits[tp->index].low_warn) {
  157. printk(KERN_WARNING "temp%d: "
  158. "Below safe ambient operating temperature, %d C.\n",
  159. tp->index, (int) tp->curr_amb_temp);
  160. ret = 1;
  161. }
  162. if (ret)
  163. *last_warn = jiffies;
  164. } else if (tp->curr_amb_temp >= amb_temp_limits[tp->index].high_warn ||
  165. tp->curr_amb_temp < amb_temp_limits[tp->index].low_warn)
  166. ret = 1;
  167. /* Now check the shutdown limits. */
  168. if (tp->curr_amb_temp >= amb_temp_limits[tp->index].high_shutdown ||
  169. tp->curr_amb_temp < amb_temp_limits[tp->index].low_shutdown) {
  170. do_envctrl_shutdown(tp);
  171. ret = 1;
  172. }
  173. if (ret) {
  174. tp->fan_todo[FAN_AMBIENT] = FAN_FULLBLAST;
  175. } else if ((tick & (8 - 1)) == 0) {
  176. s8 amb_goal_hi = amb_temp_limits[tp->index].high_warn - 10;
  177. s8 amb_goal_lo;
  178. amb_goal_lo = amb_goal_hi - 3;
  179. /* We do not try to avoid 'too cold' events. Basically we
  180. * only try to deal with over-heating and fan noise reduction.
  181. */
  182. if (tp->avg_amb_temp < amb_goal_hi) {
  183. if (tp->avg_amb_temp >= amb_goal_lo)
  184. tp->fan_todo[FAN_AMBIENT] = FAN_SAME;
  185. else
  186. tp->fan_todo[FAN_AMBIENT] = FAN_SLOWER;
  187. } else {
  188. tp->fan_todo[FAN_AMBIENT] = FAN_FASTER;
  189. }
  190. } else {
  191. tp->fan_todo[FAN_AMBIENT] = FAN_SAME;
  192. }
  193. }
  194. static void analyze_cpu_temp(struct bbc_cpu_temperature *tp, unsigned long *last_warn, int tick)
  195. {
  196. int ret = 0;
  197. if (time_after(jiffies, (*last_warn + WARN_INTERVAL))) {
  198. if (tp->curr_cpu_temp >=
  199. cpu_temp_limits[tp->index].high_warn) {
  200. printk(KERN_WARNING "temp%d: "
  201. "Above safe CPU operating temperature, %d C.\n",
  202. tp->index, (int) tp->curr_cpu_temp);
  203. ret = 1;
  204. } else if (tp->curr_cpu_temp <
  205. cpu_temp_limits[tp->index].low_warn) {
  206. printk(KERN_WARNING "temp%d: "
  207. "Below safe CPU operating temperature, %d C.\n",
  208. tp->index, (int) tp->curr_cpu_temp);
  209. ret = 1;
  210. }
  211. if (ret)
  212. *last_warn = jiffies;
  213. } else if (tp->curr_cpu_temp >= cpu_temp_limits[tp->index].high_warn ||
  214. tp->curr_cpu_temp < cpu_temp_limits[tp->index].low_warn)
  215. ret = 1;
  216. /* Now check the shutdown limits. */
  217. if (tp->curr_cpu_temp >= cpu_temp_limits[tp->index].high_shutdown ||
  218. tp->curr_cpu_temp < cpu_temp_limits[tp->index].low_shutdown) {
  219. do_envctrl_shutdown(tp);
  220. ret = 1;
  221. }
  222. if (ret) {
  223. tp->fan_todo[FAN_CPU] = FAN_FULLBLAST;
  224. } else if ((tick & (8 - 1)) == 0) {
  225. s8 cpu_goal_hi = cpu_temp_limits[tp->index].high_warn - 10;
  226. s8 cpu_goal_lo;
  227. cpu_goal_lo = cpu_goal_hi - 3;
  228. /* We do not try to avoid 'too cold' events. Basically we
  229. * only try to deal with over-heating and fan noise reduction.
  230. */
  231. if (tp->avg_cpu_temp < cpu_goal_hi) {
  232. if (tp->avg_cpu_temp >= cpu_goal_lo)
  233. tp->fan_todo[FAN_CPU] = FAN_SAME;
  234. else
  235. tp->fan_todo[FAN_CPU] = FAN_SLOWER;
  236. } else {
  237. tp->fan_todo[FAN_CPU] = FAN_FASTER;
  238. }
  239. } else {
  240. tp->fan_todo[FAN_CPU] = FAN_SAME;
  241. }
  242. }
  243. static void analyze_temps(struct bbc_cpu_temperature *tp, unsigned long *last_warn)
  244. {
  245. tp->avg_amb_temp = (s8)((int)((int)tp->avg_amb_temp + (int)tp->curr_amb_temp) / 2);
  246. tp->avg_cpu_temp = (s8)((int)((int)tp->avg_cpu_temp + (int)tp->curr_cpu_temp) / 2);
  247. analyze_ambient_temp(tp, last_warn, tp->sample_tick);
  248. analyze_cpu_temp(tp, last_warn, tp->sample_tick);
  249. tp->sample_tick++;
  250. }
  251. static enum fan_action prioritize_fan_action(int which_fan)
  252. {
  253. struct bbc_cpu_temperature *tp;
  254. enum fan_action decision = FAN_STATE_MAX;
  255. /* Basically, prioritize what the temperature sensors
  256. * recommend we do, and perform that action on all the
  257. * fans.
  258. */
  259. list_for_each_entry(tp, &all_temps, glob_list) {
  260. if (tp->fan_todo[which_fan] == FAN_FULLBLAST) {
  261. decision = FAN_FULLBLAST;
  262. break;
  263. }
  264. if (tp->fan_todo[which_fan] == FAN_SAME &&
  265. decision != FAN_FASTER)
  266. decision = FAN_SAME;
  267. else if (tp->fan_todo[which_fan] == FAN_FASTER)
  268. decision = FAN_FASTER;
  269. else if (decision != FAN_FASTER &&
  270. decision != FAN_SAME &&
  271. tp->fan_todo[which_fan] == FAN_SLOWER)
  272. decision = FAN_SLOWER;
  273. }
  274. if (decision == FAN_STATE_MAX)
  275. decision = FAN_SAME;
  276. return decision;
  277. }
  278. static int maybe_new_ambient_fan_speed(struct bbc_fan_control *fp)
  279. {
  280. enum fan_action decision = prioritize_fan_action(FAN_AMBIENT);
  281. int ret;
  282. if (decision == FAN_SAME)
  283. return 0;
  284. ret = 1;
  285. if (decision == FAN_FULLBLAST) {
  286. if (fp->system_fan_speed >= FAN_SPEED_MAX)
  287. ret = 0;
  288. else
  289. fp->system_fan_speed = FAN_SPEED_MAX;
  290. } else {
  291. if (decision == FAN_FASTER) {
  292. if (fp->system_fan_speed >= FAN_SPEED_MAX)
  293. ret = 0;
  294. else
  295. fp->system_fan_speed += 2;
  296. } else {
  297. int orig_speed = fp->system_fan_speed;
  298. if (orig_speed <= FAN_SPEED_MIN ||
  299. orig_speed <= (fp->cpu_fan_speed - 3))
  300. ret = 0;
  301. else
  302. fp->system_fan_speed -= 1;
  303. }
  304. }
  305. return ret;
  306. }
  307. static int maybe_new_cpu_fan_speed(struct bbc_fan_control *fp)
  308. {
  309. enum fan_action decision = prioritize_fan_action(FAN_CPU);
  310. int ret;
  311. if (decision == FAN_SAME)
  312. return 0;
  313. ret = 1;
  314. if (decision == FAN_FULLBLAST) {
  315. if (fp->cpu_fan_speed >= FAN_SPEED_MAX)
  316. ret = 0;
  317. else
  318. fp->cpu_fan_speed = FAN_SPEED_MAX;
  319. } else {
  320. if (decision == FAN_FASTER) {
  321. if (fp->cpu_fan_speed >= FAN_SPEED_MAX)
  322. ret = 0;
  323. else {
  324. fp->cpu_fan_speed += 2;
  325. if (fp->system_fan_speed <
  326. (fp->cpu_fan_speed - 3))
  327. fp->system_fan_speed =
  328. fp->cpu_fan_speed - 3;
  329. }
  330. } else {
  331. if (fp->cpu_fan_speed <= FAN_SPEED_MIN)
  332. ret = 0;
  333. else
  334. fp->cpu_fan_speed -= 1;
  335. }
  336. }
  337. return ret;
  338. }
  339. static void maybe_new_fan_speeds(struct bbc_fan_control *fp)
  340. {
  341. int new;
  342. new = maybe_new_ambient_fan_speed(fp);
  343. new |= maybe_new_cpu_fan_speed(fp);
  344. if (new)
  345. set_fan_speeds(fp);
  346. }
  347. static void fans_full_blast(void)
  348. {
  349. struct bbc_fan_control *fp;
  350. /* Since we will not be monitoring things anymore, put
  351. * the fans on full blast.
  352. */
  353. list_for_each_entry(fp, &all_fans, glob_list) {
  354. fp->cpu_fan_speed = FAN_SPEED_MAX;
  355. fp->system_fan_speed = FAN_SPEED_MAX;
  356. fp->psupply_fan_on = 1;
  357. set_fan_speeds(fp);
  358. }
  359. }
  360. #define POLL_INTERVAL (5 * 1000)
  361. static unsigned long last_warning_jiffies;
  362. static struct task_struct *kenvctrld_task;
  363. static int kenvctrld(void *__unused)
  364. {
  365. printk(KERN_INFO "bbc_envctrl: kenvctrld starting...\n");
  366. last_warning_jiffies = jiffies - WARN_INTERVAL;
  367. for (;;) {
  368. struct bbc_cpu_temperature *tp;
  369. struct bbc_fan_control *fp;
  370. msleep_interruptible(POLL_INTERVAL);
  371. if (kthread_should_stop())
  372. break;
  373. list_for_each_entry(tp, &all_temps, glob_list) {
  374. get_current_temps(tp);
  375. analyze_temps(tp, &last_warning_jiffies);
  376. }
  377. list_for_each_entry(fp, &all_fans, glob_list)
  378. maybe_new_fan_speeds(fp);
  379. }
  380. printk(KERN_INFO "bbc_envctrl: kenvctrld exiting...\n");
  381. fans_full_blast();
  382. return 0;
  383. }
  384. static void attach_one_temp(struct bbc_i2c_bus *bp, struct platform_device *op,
  385. int temp_idx)
  386. {
  387. struct bbc_cpu_temperature *tp;
  388. tp = kzalloc(sizeof(*tp), GFP_KERNEL);
  389. if (!tp)
  390. return;
  391. INIT_LIST_HEAD(&tp->bp_list);
  392. INIT_LIST_HEAD(&tp->glob_list);
  393. tp->client = bbc_i2c_attach(bp, op);
  394. if (!tp->client) {
  395. kfree(tp);
  396. return;
  397. }
  398. tp->index = temp_idx;
  399. list_add(&tp->glob_list, &all_temps);
  400. list_add(&tp->bp_list, &bp->temps);
  401. /* Tell it to convert once every 5 seconds, clear all cfg
  402. * bits.
  403. */
  404. bbc_i2c_writeb(tp->client, 0x00, MAX1617_WR_CFG_BYTE);
  405. bbc_i2c_writeb(tp->client, 0x02, MAX1617_WR_CVRATE_BYTE);
  406. /* Program the hard temperature limits into the chip. */
  407. bbc_i2c_writeb(tp->client, amb_temp_limits[tp->index].high_pwroff,
  408. MAX1617_WR_AMB_HIGHLIM);
  409. bbc_i2c_writeb(tp->client, amb_temp_limits[tp->index].low_pwroff,
  410. MAX1617_WR_AMB_LOWLIM);
  411. bbc_i2c_writeb(tp->client, cpu_temp_limits[tp->index].high_pwroff,
  412. MAX1617_WR_CPU_HIGHLIM);
  413. bbc_i2c_writeb(tp->client, cpu_temp_limits[tp->index].low_pwroff,
  414. MAX1617_WR_CPU_LOWLIM);
  415. get_current_temps(tp);
  416. tp->prev_cpu_temp = tp->avg_cpu_temp = tp->curr_cpu_temp;
  417. tp->prev_amb_temp = tp->avg_amb_temp = tp->curr_amb_temp;
  418. tp->fan_todo[FAN_AMBIENT] = FAN_SAME;
  419. tp->fan_todo[FAN_CPU] = FAN_SAME;
  420. }
  421. static void attach_one_fan(struct bbc_i2c_bus *bp, struct platform_device *op,
  422. int fan_idx)
  423. {
  424. struct bbc_fan_control *fp;
  425. fp = kzalloc(sizeof(*fp), GFP_KERNEL);
  426. if (!fp)
  427. return;
  428. INIT_LIST_HEAD(&fp->bp_list);
  429. INIT_LIST_HEAD(&fp->glob_list);
  430. fp->client = bbc_i2c_attach(bp, op);
  431. if (!fp->client) {
  432. kfree(fp);
  433. return;
  434. }
  435. fp->index = fan_idx;
  436. list_add(&fp->glob_list, &all_fans);
  437. list_add(&fp->bp_list, &bp->fans);
  438. /* The i2c device controlling the fans is write-only.
  439. * So the only way to keep track of the current power
  440. * level fed to the fans is via software. Choose half
  441. * power for cpu/system and 'on' fo the powersupply fan
  442. * and set it now.
  443. */
  444. fp->psupply_fan_on = 1;
  445. fp->cpu_fan_speed = (FAN_SPEED_MAX - FAN_SPEED_MIN) / 2;
  446. fp->cpu_fan_speed += FAN_SPEED_MIN;
  447. fp->system_fan_speed = (FAN_SPEED_MAX - FAN_SPEED_MIN) / 2;
  448. fp->system_fan_speed += FAN_SPEED_MIN;
  449. set_fan_speeds(fp);
  450. }
  451. static void destroy_one_temp(struct bbc_cpu_temperature *tp)
  452. {
  453. bbc_i2c_detach(tp->client);
  454. kfree(tp);
  455. }
  456. static void destroy_all_temps(struct bbc_i2c_bus *bp)
  457. {
  458. struct bbc_cpu_temperature *tp, *tpos;
  459. list_for_each_entry_safe(tp, tpos, &bp->temps, bp_list) {
  460. list_del(&tp->bp_list);
  461. list_del(&tp->glob_list);
  462. destroy_one_temp(tp);
  463. }
  464. }
  465. static void destroy_one_fan(struct bbc_fan_control *fp)
  466. {
  467. bbc_i2c_detach(fp->client);
  468. kfree(fp);
  469. }
  470. static void destroy_all_fans(struct bbc_i2c_bus *bp)
  471. {
  472. struct bbc_fan_control *fp, *fpos;
  473. list_for_each_entry_safe(fp, fpos, &bp->fans, bp_list) {
  474. list_del(&fp->bp_list);
  475. list_del(&fp->glob_list);
  476. destroy_one_fan(fp);
  477. }
  478. }
  479. int bbc_envctrl_init(struct bbc_i2c_bus *bp)
  480. {
  481. struct platform_device *op;
  482. int temp_index = 0;
  483. int fan_index = 0;
  484. int devidx = 0;
  485. while ((op = bbc_i2c_getdev(bp, devidx++)) != NULL) {
  486. if (!strcmp(op->dev.of_node->name, "temperature"))
  487. attach_one_temp(bp, op, temp_index++);
  488. if (!strcmp(op->dev.of_node->name, "fan-control"))
  489. attach_one_fan(bp, op, fan_index++);
  490. }
  491. if (temp_index != 0 && fan_index != 0) {
  492. kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld");
  493. if (IS_ERR(kenvctrld_task)) {
  494. int err = PTR_ERR(kenvctrld_task);
  495. kenvctrld_task = NULL;
  496. destroy_all_temps(bp);
  497. destroy_all_fans(bp);
  498. return err;
  499. }
  500. }
  501. return 0;
  502. }
  503. void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp)
  504. {
  505. if (kenvctrld_task)
  506. kthread_stop(kenvctrld_task);
  507. destroy_all_temps(bp);
  508. destroy_all_fans(bp);
  509. }