bbc_envctrl.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  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. orderly_poweroff(true);
  142. }
  143. #define WARN_INTERVAL (30 * HZ)
  144. static void analyze_ambient_temp(struct bbc_cpu_temperature *tp, unsigned long *last_warn, int tick)
  145. {
  146. int ret = 0;
  147. if (time_after(jiffies, (*last_warn + WARN_INTERVAL))) {
  148. if (tp->curr_amb_temp >=
  149. amb_temp_limits[tp->index].high_warn) {
  150. printk(KERN_WARNING "temp%d: "
  151. "Above safe ambient operating temperature, %d C.\n",
  152. tp->index, (int) tp->curr_amb_temp);
  153. ret = 1;
  154. } else if (tp->curr_amb_temp <
  155. amb_temp_limits[tp->index].low_warn) {
  156. printk(KERN_WARNING "temp%d: "
  157. "Below safe ambient operating temperature, %d C.\n",
  158. tp->index, (int) tp->curr_amb_temp);
  159. ret = 1;
  160. }
  161. if (ret)
  162. *last_warn = jiffies;
  163. } else if (tp->curr_amb_temp >= amb_temp_limits[tp->index].high_warn ||
  164. tp->curr_amb_temp < amb_temp_limits[tp->index].low_warn)
  165. ret = 1;
  166. /* Now check the shutdown limits. */
  167. if (tp->curr_amb_temp >= amb_temp_limits[tp->index].high_shutdown ||
  168. tp->curr_amb_temp < amb_temp_limits[tp->index].low_shutdown) {
  169. do_envctrl_shutdown(tp);
  170. ret = 1;
  171. }
  172. if (ret) {
  173. tp->fan_todo[FAN_AMBIENT] = FAN_FULLBLAST;
  174. } else if ((tick & (8 - 1)) == 0) {
  175. s8 amb_goal_hi = amb_temp_limits[tp->index].high_warn - 10;
  176. s8 amb_goal_lo;
  177. amb_goal_lo = amb_goal_hi - 3;
  178. /* We do not try to avoid 'too cold' events. Basically we
  179. * only try to deal with over-heating and fan noise reduction.
  180. */
  181. if (tp->avg_amb_temp < amb_goal_hi) {
  182. if (tp->avg_amb_temp >= amb_goal_lo)
  183. tp->fan_todo[FAN_AMBIENT] = FAN_SAME;
  184. else
  185. tp->fan_todo[FAN_AMBIENT] = FAN_SLOWER;
  186. } else {
  187. tp->fan_todo[FAN_AMBIENT] = FAN_FASTER;
  188. }
  189. } else {
  190. tp->fan_todo[FAN_AMBIENT] = FAN_SAME;
  191. }
  192. }
  193. static void analyze_cpu_temp(struct bbc_cpu_temperature *tp, unsigned long *last_warn, int tick)
  194. {
  195. int ret = 0;
  196. if (time_after(jiffies, (*last_warn + WARN_INTERVAL))) {
  197. if (tp->curr_cpu_temp >=
  198. cpu_temp_limits[tp->index].high_warn) {
  199. printk(KERN_WARNING "temp%d: "
  200. "Above safe CPU operating temperature, %d C.\n",
  201. tp->index, (int) tp->curr_cpu_temp);
  202. ret = 1;
  203. } else if (tp->curr_cpu_temp <
  204. cpu_temp_limits[tp->index].low_warn) {
  205. printk(KERN_WARNING "temp%d: "
  206. "Below safe CPU operating temperature, %d C.\n",
  207. tp->index, (int) tp->curr_cpu_temp);
  208. ret = 1;
  209. }
  210. if (ret)
  211. *last_warn = jiffies;
  212. } else if (tp->curr_cpu_temp >= cpu_temp_limits[tp->index].high_warn ||
  213. tp->curr_cpu_temp < cpu_temp_limits[tp->index].low_warn)
  214. ret = 1;
  215. /* Now check the shutdown limits. */
  216. if (tp->curr_cpu_temp >= cpu_temp_limits[tp->index].high_shutdown ||
  217. tp->curr_cpu_temp < cpu_temp_limits[tp->index].low_shutdown) {
  218. do_envctrl_shutdown(tp);
  219. ret = 1;
  220. }
  221. if (ret) {
  222. tp->fan_todo[FAN_CPU] = FAN_FULLBLAST;
  223. } else if ((tick & (8 - 1)) == 0) {
  224. s8 cpu_goal_hi = cpu_temp_limits[tp->index].high_warn - 10;
  225. s8 cpu_goal_lo;
  226. cpu_goal_lo = cpu_goal_hi - 3;
  227. /* We do not try to avoid 'too cold' events. Basically we
  228. * only try to deal with over-heating and fan noise reduction.
  229. */
  230. if (tp->avg_cpu_temp < cpu_goal_hi) {
  231. if (tp->avg_cpu_temp >= cpu_goal_lo)
  232. tp->fan_todo[FAN_CPU] = FAN_SAME;
  233. else
  234. tp->fan_todo[FAN_CPU] = FAN_SLOWER;
  235. } else {
  236. tp->fan_todo[FAN_CPU] = FAN_FASTER;
  237. }
  238. } else {
  239. tp->fan_todo[FAN_CPU] = FAN_SAME;
  240. }
  241. }
  242. static void analyze_temps(struct bbc_cpu_temperature *tp, unsigned long *last_warn)
  243. {
  244. tp->avg_amb_temp = (s8)((int)((int)tp->avg_amb_temp + (int)tp->curr_amb_temp) / 2);
  245. tp->avg_cpu_temp = (s8)((int)((int)tp->avg_cpu_temp + (int)tp->curr_cpu_temp) / 2);
  246. analyze_ambient_temp(tp, last_warn, tp->sample_tick);
  247. analyze_cpu_temp(tp, last_warn, tp->sample_tick);
  248. tp->sample_tick++;
  249. }
  250. static enum fan_action prioritize_fan_action(int which_fan)
  251. {
  252. struct bbc_cpu_temperature *tp;
  253. enum fan_action decision = FAN_STATE_MAX;
  254. /* Basically, prioritize what the temperature sensors
  255. * recommend we do, and perform that action on all the
  256. * fans.
  257. */
  258. list_for_each_entry(tp, &all_temps, glob_list) {
  259. if (tp->fan_todo[which_fan] == FAN_FULLBLAST) {
  260. decision = FAN_FULLBLAST;
  261. break;
  262. }
  263. if (tp->fan_todo[which_fan] == FAN_SAME &&
  264. decision != FAN_FASTER)
  265. decision = FAN_SAME;
  266. else if (tp->fan_todo[which_fan] == FAN_FASTER)
  267. decision = FAN_FASTER;
  268. else if (decision != FAN_FASTER &&
  269. decision != FAN_SAME &&
  270. tp->fan_todo[which_fan] == FAN_SLOWER)
  271. decision = FAN_SLOWER;
  272. }
  273. if (decision == FAN_STATE_MAX)
  274. decision = FAN_SAME;
  275. return decision;
  276. }
  277. static int maybe_new_ambient_fan_speed(struct bbc_fan_control *fp)
  278. {
  279. enum fan_action decision = prioritize_fan_action(FAN_AMBIENT);
  280. int ret;
  281. if (decision == FAN_SAME)
  282. return 0;
  283. ret = 1;
  284. if (decision == FAN_FULLBLAST) {
  285. if (fp->system_fan_speed >= FAN_SPEED_MAX)
  286. ret = 0;
  287. else
  288. fp->system_fan_speed = FAN_SPEED_MAX;
  289. } else {
  290. if (decision == FAN_FASTER) {
  291. if (fp->system_fan_speed >= FAN_SPEED_MAX)
  292. ret = 0;
  293. else
  294. fp->system_fan_speed += 2;
  295. } else {
  296. int orig_speed = fp->system_fan_speed;
  297. if (orig_speed <= FAN_SPEED_MIN ||
  298. orig_speed <= (fp->cpu_fan_speed - 3))
  299. ret = 0;
  300. else
  301. fp->system_fan_speed -= 1;
  302. }
  303. }
  304. return ret;
  305. }
  306. static int maybe_new_cpu_fan_speed(struct bbc_fan_control *fp)
  307. {
  308. enum fan_action decision = prioritize_fan_action(FAN_CPU);
  309. int ret;
  310. if (decision == FAN_SAME)
  311. return 0;
  312. ret = 1;
  313. if (decision == FAN_FULLBLAST) {
  314. if (fp->cpu_fan_speed >= FAN_SPEED_MAX)
  315. ret = 0;
  316. else
  317. fp->cpu_fan_speed = FAN_SPEED_MAX;
  318. } else {
  319. if (decision == FAN_FASTER) {
  320. if (fp->cpu_fan_speed >= FAN_SPEED_MAX)
  321. ret = 0;
  322. else {
  323. fp->cpu_fan_speed += 2;
  324. if (fp->system_fan_speed <
  325. (fp->cpu_fan_speed - 3))
  326. fp->system_fan_speed =
  327. fp->cpu_fan_speed - 3;
  328. }
  329. } else {
  330. if (fp->cpu_fan_speed <= FAN_SPEED_MIN)
  331. ret = 0;
  332. else
  333. fp->cpu_fan_speed -= 1;
  334. }
  335. }
  336. return ret;
  337. }
  338. static void maybe_new_fan_speeds(struct bbc_fan_control *fp)
  339. {
  340. int new;
  341. new = maybe_new_ambient_fan_speed(fp);
  342. new |= maybe_new_cpu_fan_speed(fp);
  343. if (new)
  344. set_fan_speeds(fp);
  345. }
  346. static void fans_full_blast(void)
  347. {
  348. struct bbc_fan_control *fp;
  349. /* Since we will not be monitoring things anymore, put
  350. * the fans on full blast.
  351. */
  352. list_for_each_entry(fp, &all_fans, glob_list) {
  353. fp->cpu_fan_speed = FAN_SPEED_MAX;
  354. fp->system_fan_speed = FAN_SPEED_MAX;
  355. fp->psupply_fan_on = 1;
  356. set_fan_speeds(fp);
  357. }
  358. }
  359. #define POLL_INTERVAL (5 * 1000)
  360. static unsigned long last_warning_jiffies;
  361. static struct task_struct *kenvctrld_task;
  362. static int kenvctrld(void *__unused)
  363. {
  364. printk(KERN_INFO "bbc_envctrl: kenvctrld starting...\n");
  365. last_warning_jiffies = jiffies - WARN_INTERVAL;
  366. for (;;) {
  367. struct bbc_cpu_temperature *tp;
  368. struct bbc_fan_control *fp;
  369. msleep_interruptible(POLL_INTERVAL);
  370. if (kthread_should_stop())
  371. break;
  372. list_for_each_entry(tp, &all_temps, glob_list) {
  373. get_current_temps(tp);
  374. analyze_temps(tp, &last_warning_jiffies);
  375. }
  376. list_for_each_entry(fp, &all_fans, glob_list)
  377. maybe_new_fan_speeds(fp);
  378. }
  379. printk(KERN_INFO "bbc_envctrl: kenvctrld exiting...\n");
  380. fans_full_blast();
  381. return 0;
  382. }
  383. static void attach_one_temp(struct bbc_i2c_bus *bp, struct platform_device *op,
  384. int temp_idx)
  385. {
  386. struct bbc_cpu_temperature *tp;
  387. tp = kzalloc(sizeof(*tp), GFP_KERNEL);
  388. if (!tp)
  389. return;
  390. INIT_LIST_HEAD(&tp->bp_list);
  391. INIT_LIST_HEAD(&tp->glob_list);
  392. tp->client = bbc_i2c_attach(bp, op);
  393. if (!tp->client) {
  394. kfree(tp);
  395. return;
  396. }
  397. tp->index = temp_idx;
  398. list_add(&tp->glob_list, &all_temps);
  399. list_add(&tp->bp_list, &bp->temps);
  400. /* Tell it to convert once every 5 seconds, clear all cfg
  401. * bits.
  402. */
  403. bbc_i2c_writeb(tp->client, 0x00, MAX1617_WR_CFG_BYTE);
  404. bbc_i2c_writeb(tp->client, 0x02, MAX1617_WR_CVRATE_BYTE);
  405. /* Program the hard temperature limits into the chip. */
  406. bbc_i2c_writeb(tp->client, amb_temp_limits[tp->index].high_pwroff,
  407. MAX1617_WR_AMB_HIGHLIM);
  408. bbc_i2c_writeb(tp->client, amb_temp_limits[tp->index].low_pwroff,
  409. MAX1617_WR_AMB_LOWLIM);
  410. bbc_i2c_writeb(tp->client, cpu_temp_limits[tp->index].high_pwroff,
  411. MAX1617_WR_CPU_HIGHLIM);
  412. bbc_i2c_writeb(tp->client, cpu_temp_limits[tp->index].low_pwroff,
  413. MAX1617_WR_CPU_LOWLIM);
  414. get_current_temps(tp);
  415. tp->prev_cpu_temp = tp->avg_cpu_temp = tp->curr_cpu_temp;
  416. tp->prev_amb_temp = tp->avg_amb_temp = tp->curr_amb_temp;
  417. tp->fan_todo[FAN_AMBIENT] = FAN_SAME;
  418. tp->fan_todo[FAN_CPU] = FAN_SAME;
  419. }
  420. static void attach_one_fan(struct bbc_i2c_bus *bp, struct platform_device *op,
  421. int fan_idx)
  422. {
  423. struct bbc_fan_control *fp;
  424. fp = kzalloc(sizeof(*fp), GFP_KERNEL);
  425. if (!fp)
  426. return;
  427. INIT_LIST_HEAD(&fp->bp_list);
  428. INIT_LIST_HEAD(&fp->glob_list);
  429. fp->client = bbc_i2c_attach(bp, op);
  430. if (!fp->client) {
  431. kfree(fp);
  432. return;
  433. }
  434. fp->index = fan_idx;
  435. list_add(&fp->glob_list, &all_fans);
  436. list_add(&fp->bp_list, &bp->fans);
  437. /* The i2c device controlling the fans is write-only.
  438. * So the only way to keep track of the current power
  439. * level fed to the fans is via software. Choose half
  440. * power for cpu/system and 'on' fo the powersupply fan
  441. * and set it now.
  442. */
  443. fp->psupply_fan_on = 1;
  444. fp->cpu_fan_speed = (FAN_SPEED_MAX - FAN_SPEED_MIN) / 2;
  445. fp->cpu_fan_speed += FAN_SPEED_MIN;
  446. fp->system_fan_speed = (FAN_SPEED_MAX - FAN_SPEED_MIN) / 2;
  447. fp->system_fan_speed += FAN_SPEED_MIN;
  448. set_fan_speeds(fp);
  449. }
  450. static void destroy_one_temp(struct bbc_cpu_temperature *tp)
  451. {
  452. bbc_i2c_detach(tp->client);
  453. kfree(tp);
  454. }
  455. static void destroy_all_temps(struct bbc_i2c_bus *bp)
  456. {
  457. struct bbc_cpu_temperature *tp, *tpos;
  458. list_for_each_entry_safe(tp, tpos, &bp->temps, bp_list) {
  459. list_del(&tp->bp_list);
  460. list_del(&tp->glob_list);
  461. destroy_one_temp(tp);
  462. }
  463. }
  464. static void destroy_one_fan(struct bbc_fan_control *fp)
  465. {
  466. bbc_i2c_detach(fp->client);
  467. kfree(fp);
  468. }
  469. static void destroy_all_fans(struct bbc_i2c_bus *bp)
  470. {
  471. struct bbc_fan_control *fp, *fpos;
  472. list_for_each_entry_safe(fp, fpos, &bp->fans, bp_list) {
  473. list_del(&fp->bp_list);
  474. list_del(&fp->glob_list);
  475. destroy_one_fan(fp);
  476. }
  477. }
  478. int bbc_envctrl_init(struct bbc_i2c_bus *bp)
  479. {
  480. struct platform_device *op;
  481. int temp_index = 0;
  482. int fan_index = 0;
  483. int devidx = 0;
  484. while ((op = bbc_i2c_getdev(bp, devidx++)) != NULL) {
  485. if (!strcmp(op->dev.of_node->name, "temperature"))
  486. attach_one_temp(bp, op, temp_index++);
  487. if (!strcmp(op->dev.of_node->name, "fan-control"))
  488. attach_one_fan(bp, op, fan_index++);
  489. }
  490. if (temp_index != 0 && fan_index != 0) {
  491. kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld");
  492. if (IS_ERR(kenvctrld_task)) {
  493. int err = PTR_ERR(kenvctrld_task);
  494. kenvctrld_task = NULL;
  495. destroy_all_temps(bp);
  496. destroy_all_fans(bp);
  497. return err;
  498. }
  499. }
  500. return 0;
  501. }
  502. void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp)
  503. {
  504. if (kenvctrld_task)
  505. kthread_stop(kenvctrld_task);
  506. destroy_all_temps(bp);
  507. destroy_all_fans(bp);
  508. }