bbc_envctrl.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  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. tp->client = bbc_i2c_attach(bp, op);
  392. if (!tp->client) {
  393. kfree(tp);
  394. return;
  395. }
  396. tp->index = temp_idx;
  397. list_add(&tp->glob_list, &all_temps);
  398. list_add(&tp->bp_list, &bp->temps);
  399. /* Tell it to convert once every 5 seconds, clear all cfg
  400. * bits.
  401. */
  402. bbc_i2c_writeb(tp->client, 0x00, MAX1617_WR_CFG_BYTE);
  403. bbc_i2c_writeb(tp->client, 0x02, MAX1617_WR_CVRATE_BYTE);
  404. /* Program the hard temperature limits into the chip. */
  405. bbc_i2c_writeb(tp->client, amb_temp_limits[tp->index].high_pwroff,
  406. MAX1617_WR_AMB_HIGHLIM);
  407. bbc_i2c_writeb(tp->client, amb_temp_limits[tp->index].low_pwroff,
  408. MAX1617_WR_AMB_LOWLIM);
  409. bbc_i2c_writeb(tp->client, cpu_temp_limits[tp->index].high_pwroff,
  410. MAX1617_WR_CPU_HIGHLIM);
  411. bbc_i2c_writeb(tp->client, cpu_temp_limits[tp->index].low_pwroff,
  412. MAX1617_WR_CPU_LOWLIM);
  413. get_current_temps(tp);
  414. tp->prev_cpu_temp = tp->avg_cpu_temp = tp->curr_cpu_temp;
  415. tp->prev_amb_temp = tp->avg_amb_temp = tp->curr_amb_temp;
  416. tp->fan_todo[FAN_AMBIENT] = FAN_SAME;
  417. tp->fan_todo[FAN_CPU] = FAN_SAME;
  418. }
  419. static void attach_one_fan(struct bbc_i2c_bus *bp, struct platform_device *op,
  420. int fan_idx)
  421. {
  422. struct bbc_fan_control *fp;
  423. fp = kzalloc(sizeof(*fp), GFP_KERNEL);
  424. if (!fp)
  425. return;
  426. fp->client = bbc_i2c_attach(bp, op);
  427. if (!fp->client) {
  428. kfree(fp);
  429. return;
  430. }
  431. fp->index = fan_idx;
  432. list_add(&fp->glob_list, &all_fans);
  433. list_add(&fp->bp_list, &bp->fans);
  434. /* The i2c device controlling the fans is write-only.
  435. * So the only way to keep track of the current power
  436. * level fed to the fans is via software. Choose half
  437. * power for cpu/system and 'on' fo the powersupply fan
  438. * and set it now.
  439. */
  440. fp->psupply_fan_on = 1;
  441. fp->cpu_fan_speed = (FAN_SPEED_MAX - FAN_SPEED_MIN) / 2;
  442. fp->cpu_fan_speed += FAN_SPEED_MIN;
  443. fp->system_fan_speed = (FAN_SPEED_MAX - FAN_SPEED_MIN) / 2;
  444. fp->system_fan_speed += FAN_SPEED_MIN;
  445. set_fan_speeds(fp);
  446. }
  447. static void destroy_one_temp(struct bbc_cpu_temperature *tp)
  448. {
  449. bbc_i2c_detach(tp->client);
  450. kfree(tp);
  451. }
  452. static void destroy_all_temps(struct bbc_i2c_bus *bp)
  453. {
  454. struct bbc_cpu_temperature *tp, *tpos;
  455. list_for_each_entry_safe(tp, tpos, &bp->temps, bp_list) {
  456. list_del(&tp->bp_list);
  457. list_del(&tp->glob_list);
  458. destroy_one_temp(tp);
  459. }
  460. }
  461. static void destroy_one_fan(struct bbc_fan_control *fp)
  462. {
  463. bbc_i2c_detach(fp->client);
  464. kfree(fp);
  465. }
  466. static void destroy_all_fans(struct bbc_i2c_bus *bp)
  467. {
  468. struct bbc_fan_control *fp, *fpos;
  469. list_for_each_entry_safe(fp, fpos, &bp->fans, bp_list) {
  470. list_del(&fp->bp_list);
  471. list_del(&fp->glob_list);
  472. destroy_one_fan(fp);
  473. }
  474. }
  475. int bbc_envctrl_init(struct bbc_i2c_bus *bp)
  476. {
  477. struct platform_device *op;
  478. int temp_index = 0;
  479. int fan_index = 0;
  480. int devidx = 0;
  481. while ((op = bbc_i2c_getdev(bp, devidx++)) != NULL) {
  482. if (!strcmp(op->dev.of_node->name, "temperature"))
  483. attach_one_temp(bp, op, temp_index++);
  484. if (!strcmp(op->dev.of_node->name, "fan-control"))
  485. attach_one_fan(bp, op, fan_index++);
  486. }
  487. if (temp_index != 0 && fan_index != 0) {
  488. kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld");
  489. if (IS_ERR(kenvctrld_task)) {
  490. int err = PTR_ERR(kenvctrld_task);
  491. kenvctrld_task = NULL;
  492. destroy_all_temps(bp);
  493. destroy_all_fans(bp);
  494. return err;
  495. }
  496. }
  497. return 0;
  498. }
  499. void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp)
  500. {
  501. if (kenvctrld_task)
  502. kthread_stop(kenvctrld_task);
  503. destroy_all_temps(bp);
  504. destroy_all_fans(bp);
  505. }