smsc47m1.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  1. /*
  2. * smsc47m1.c - Part of lm_sensors, Linux kernel modules
  3. * for hardware monitoring
  4. *
  5. * Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x,
  6. * LPC47M14x, LPC47M15x, LPC47M192, LPC47M292 and LPC47M997
  7. * Super-I/O chips.
  8. *
  9. * Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
  10. * Copyright (C) 2004-2007 Jean Delvare <khali@linux-fr.org>
  11. * Ported to Linux 2.6 by Gabriele Gorla <gorlik@yahoo.com>
  12. * and Jean Delvare
  13. *
  14. * This program is free software; you can redistribute it and/or modify
  15. * it under the terms of the GNU General Public License as published by
  16. * the Free Software Foundation; either version 2 of the License, or
  17. * (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  27. */
  28. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  29. #include <linux/module.h>
  30. #include <linux/slab.h>
  31. #include <linux/ioport.h>
  32. #include <linux/jiffies.h>
  33. #include <linux/platform_device.h>
  34. #include <linux/hwmon.h>
  35. #include <linux/hwmon-sysfs.h>
  36. #include <linux/err.h>
  37. #include <linux/init.h>
  38. #include <linux/mutex.h>
  39. #include <linux/sysfs.h>
  40. #include <linux/acpi.h>
  41. #include <linux/io.h>
  42. static unsigned short force_id;
  43. module_param(force_id, ushort, 0);
  44. MODULE_PARM_DESC(force_id, "Override the detected device ID");
  45. static struct platform_device *pdev;
  46. #define DRVNAME "smsc47m1"
  47. enum chips { smsc47m1, smsc47m2 };
  48. /* Super-I/0 registers and commands */
  49. #define REG 0x2e /* The register to read/write */
  50. #define VAL 0x2f /* The value to read/write */
  51. static inline void
  52. superio_outb(int reg, int val)
  53. {
  54. outb(reg, REG);
  55. outb(val, VAL);
  56. }
  57. static inline int
  58. superio_inb(int reg)
  59. {
  60. outb(reg, REG);
  61. return inb(VAL);
  62. }
  63. /* logical device for fans is 0x0A */
  64. #define superio_select() superio_outb(0x07, 0x0A)
  65. static inline void
  66. superio_enter(void)
  67. {
  68. outb(0x55, REG);
  69. }
  70. static inline void
  71. superio_exit(void)
  72. {
  73. outb(0xAA, REG);
  74. }
  75. #define SUPERIO_REG_ACT 0x30
  76. #define SUPERIO_REG_BASE 0x60
  77. #define SUPERIO_REG_DEVID 0x20
  78. #define SUPERIO_REG_DEVREV 0x21
  79. /* Logical device registers */
  80. #define SMSC_EXTENT 0x80
  81. /* nr is 0 or 1 in the macros below */
  82. #define SMSC47M1_REG_ALARM 0x04
  83. #define SMSC47M1_REG_TPIN(nr) (0x34 - (nr))
  84. #define SMSC47M1_REG_PPIN(nr) (0x36 - (nr))
  85. #define SMSC47M1_REG_FANDIV 0x58
  86. static const u8 SMSC47M1_REG_FAN[3] = { 0x59, 0x5a, 0x6b };
  87. static const u8 SMSC47M1_REG_FAN_PRELOAD[3] = { 0x5b, 0x5c, 0x6c };
  88. static const u8 SMSC47M1_REG_PWM[3] = { 0x56, 0x57, 0x69 };
  89. #define SMSC47M2_REG_ALARM6 0x09
  90. #define SMSC47M2_REG_TPIN1 0x38
  91. #define SMSC47M2_REG_TPIN2 0x37
  92. #define SMSC47M2_REG_TPIN3 0x2d
  93. #define SMSC47M2_REG_PPIN3 0x2c
  94. #define SMSC47M2_REG_FANDIV3 0x6a
  95. #define MIN_FROM_REG(reg, div) ((reg) >= 192 ? 0 : \
  96. 983040 / ((192 - (reg)) * (div)))
  97. #define FAN_FROM_REG(reg, div, preload) ((reg) <= (preload) || (reg) == 255 ? \
  98. 0 : \
  99. 983040 / (((reg) - (preload)) * (div)))
  100. #define DIV_FROM_REG(reg) (1 << (reg))
  101. #define PWM_FROM_REG(reg) (((reg) & 0x7E) << 1)
  102. #define PWM_EN_FROM_REG(reg) ((~(reg)) & 0x01)
  103. #define PWM_TO_REG(reg) (((reg) >> 1) & 0x7E)
  104. struct smsc47m1_data {
  105. unsigned short addr;
  106. const char *name;
  107. enum chips type;
  108. struct device *hwmon_dev;
  109. struct mutex update_lock;
  110. unsigned long last_updated; /* In jiffies */
  111. u8 fan[3]; /* Register value */
  112. u8 fan_preload[3]; /* Register value */
  113. u8 fan_div[3]; /* Register encoding, shifted right */
  114. u8 alarms; /* Register encoding */
  115. u8 pwm[3]; /* Register value (bit 0 is disable) */
  116. };
  117. struct smsc47m1_sio_data {
  118. enum chips type;
  119. u8 activate; /* Remember initial device state */
  120. };
  121. static int __exit smsc47m1_remove(struct platform_device *pdev);
  122. static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
  123. int init);
  124. static inline int smsc47m1_read_value(struct smsc47m1_data *data, u8 reg)
  125. {
  126. return inb_p(data->addr + reg);
  127. }
  128. static inline void smsc47m1_write_value(struct smsc47m1_data *data, u8 reg,
  129. u8 value)
  130. {
  131. outb_p(value, data->addr + reg);
  132. }
  133. static struct platform_driver smsc47m1_driver = {
  134. .driver = {
  135. .owner = THIS_MODULE,
  136. .name = DRVNAME,
  137. },
  138. .remove = __exit_p(smsc47m1_remove),
  139. };
  140. static ssize_t get_fan(struct device *dev, struct device_attribute
  141. *devattr, char *buf)
  142. {
  143. struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  144. struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
  145. int nr = attr->index;
  146. /*
  147. * This chip (stupidly) stops monitoring fan speed if PWM is
  148. * enabled and duty cycle is 0%. This is fine if the monitoring
  149. * and control concern the same fan, but troublesome if they are
  150. * not (which could as well happen).
  151. */
  152. int rpm = (data->pwm[nr] & 0x7F) == 0x00 ? 0 :
  153. FAN_FROM_REG(data->fan[nr],
  154. DIV_FROM_REG(data->fan_div[nr]),
  155. data->fan_preload[nr]);
  156. return sprintf(buf, "%d\n", rpm);
  157. }
  158. static ssize_t get_fan_min(struct device *dev, struct device_attribute
  159. *devattr, char *buf)
  160. {
  161. struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  162. struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
  163. int nr = attr->index;
  164. int rpm = MIN_FROM_REG(data->fan_preload[nr],
  165. DIV_FROM_REG(data->fan_div[nr]));
  166. return sprintf(buf, "%d\n", rpm);
  167. }
  168. static ssize_t get_fan_div(struct device *dev, struct device_attribute
  169. *devattr, char *buf)
  170. {
  171. struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  172. struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
  173. return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index]));
  174. }
  175. static ssize_t get_fan_alarm(struct device *dev, struct device_attribute
  176. *devattr, char *buf)
  177. {
  178. int bitnr = to_sensor_dev_attr(devattr)->index;
  179. struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
  180. return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
  181. }
  182. static ssize_t get_pwm(struct device *dev, struct device_attribute
  183. *devattr, char *buf)
  184. {
  185. struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  186. struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
  187. return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[attr->index]));
  188. }
  189. static ssize_t get_pwm_en(struct device *dev, struct device_attribute
  190. *devattr, char *buf)
  191. {
  192. struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  193. struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
  194. return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[attr->index]));
  195. }
  196. static ssize_t get_alarms(struct device *dev, struct device_attribute
  197. *devattr, char *buf)
  198. {
  199. struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
  200. return sprintf(buf, "%d\n", data->alarms);
  201. }
  202. static ssize_t set_fan_min(struct device *dev, struct device_attribute
  203. *devattr, const char *buf, size_t count)
  204. {
  205. struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  206. struct smsc47m1_data *data = dev_get_drvdata(dev);
  207. int nr = attr->index;
  208. long rpmdiv;
  209. long val;
  210. int err;
  211. err = kstrtol(buf, 10, &val);
  212. if (err)
  213. return err;
  214. mutex_lock(&data->update_lock);
  215. rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]);
  216. if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) {
  217. mutex_unlock(&data->update_lock);
  218. return -EINVAL;
  219. }
  220. data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv);
  221. smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr],
  222. data->fan_preload[nr]);
  223. mutex_unlock(&data->update_lock);
  224. return count;
  225. }
  226. /*
  227. * Note: we save and restore the fan minimum here, because its value is
  228. * determined in part by the fan clock divider. This follows the principle
  229. * of least surprise; the user doesn't expect the fan minimum to change just
  230. * because the divider changed.
  231. */
  232. static ssize_t set_fan_div(struct device *dev, struct device_attribute
  233. *devattr, const char *buf, size_t count)
  234. {
  235. struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  236. struct smsc47m1_data *data = dev_get_drvdata(dev);
  237. int nr = attr->index;
  238. long new_div;
  239. int err;
  240. long tmp;
  241. u8 old_div = DIV_FROM_REG(data->fan_div[nr]);
  242. err = kstrtol(buf, 10, &new_div);
  243. if (err)
  244. return err;
  245. if (new_div == old_div) /* No change */
  246. return count;
  247. mutex_lock(&data->update_lock);
  248. switch (new_div) {
  249. case 1:
  250. data->fan_div[nr] = 0;
  251. break;
  252. case 2:
  253. data->fan_div[nr] = 1;
  254. break;
  255. case 4:
  256. data->fan_div[nr] = 2;
  257. break;
  258. case 8:
  259. data->fan_div[nr] = 3;
  260. break;
  261. default:
  262. mutex_unlock(&data->update_lock);
  263. return -EINVAL;
  264. }
  265. switch (nr) {
  266. case 0:
  267. case 1:
  268. tmp = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV)
  269. & ~(0x03 << (4 + 2 * nr));
  270. tmp |= data->fan_div[nr] << (4 + 2 * nr);
  271. smsc47m1_write_value(data, SMSC47M1_REG_FANDIV, tmp);
  272. break;
  273. case 2:
  274. tmp = smsc47m1_read_value(data, SMSC47M2_REG_FANDIV3) & 0xCF;
  275. tmp |= data->fan_div[2] << 4;
  276. smsc47m1_write_value(data, SMSC47M2_REG_FANDIV3, tmp);
  277. break;
  278. }
  279. /* Preserve fan min */
  280. tmp = 192 - (old_div * (192 - data->fan_preload[nr])
  281. + new_div / 2) / new_div;
  282. data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191);
  283. smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr],
  284. data->fan_preload[nr]);
  285. mutex_unlock(&data->update_lock);
  286. return count;
  287. }
  288. static ssize_t set_pwm(struct device *dev, struct device_attribute
  289. *devattr, const char *buf, size_t count)
  290. {
  291. struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  292. struct smsc47m1_data *data = dev_get_drvdata(dev);
  293. int nr = attr->index;
  294. long val;
  295. int err;
  296. err = kstrtol(buf, 10, &val);
  297. if (err)
  298. return err;
  299. if (val < 0 || val > 255)
  300. return -EINVAL;
  301. mutex_lock(&data->update_lock);
  302. data->pwm[nr] &= 0x81; /* Preserve additional bits */
  303. data->pwm[nr] |= PWM_TO_REG(val);
  304. smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr],
  305. data->pwm[nr]);
  306. mutex_unlock(&data->update_lock);
  307. return count;
  308. }
  309. static ssize_t set_pwm_en(struct device *dev, struct device_attribute
  310. *devattr, const char *buf, size_t count)
  311. {
  312. struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  313. struct smsc47m1_data *data = dev_get_drvdata(dev);
  314. int nr = attr->index;
  315. unsigned long val;
  316. int err;
  317. err = kstrtoul(buf, 10, &val);
  318. if (err)
  319. return err;
  320. if (val > 1)
  321. return -EINVAL;
  322. mutex_lock(&data->update_lock);
  323. data->pwm[nr] &= 0xFE; /* preserve the other bits */
  324. data->pwm[nr] |= !val;
  325. smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr],
  326. data->pwm[nr]);
  327. mutex_unlock(&data->update_lock);
  328. return count;
  329. }
  330. #define fan_present(offset) \
  331. static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan, \
  332. NULL, offset - 1); \
  333. static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
  334. get_fan_min, set_fan_min, offset - 1); \
  335. static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
  336. get_fan_div, set_fan_div, offset - 1); \
  337. static SENSOR_DEVICE_ATTR(fan##offset##_alarm, S_IRUGO, get_fan_alarm, \
  338. NULL, offset - 1); \
  339. static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
  340. get_pwm, set_pwm, offset - 1); \
  341. static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
  342. get_pwm_en, set_pwm_en, offset - 1)
  343. fan_present(1);
  344. fan_present(2);
  345. fan_present(3);
  346. static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);
  347. static ssize_t show_name(struct device *dev, struct device_attribute
  348. *devattr, char *buf)
  349. {
  350. struct smsc47m1_data *data = dev_get_drvdata(dev);
  351. return sprintf(buf, "%s\n", data->name);
  352. }
  353. static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
  354. static struct attribute *smsc47m1_attributes_fan1[] = {
  355. &sensor_dev_attr_fan1_input.dev_attr.attr,
  356. &sensor_dev_attr_fan1_min.dev_attr.attr,
  357. &sensor_dev_attr_fan1_div.dev_attr.attr,
  358. &sensor_dev_attr_fan1_alarm.dev_attr.attr,
  359. NULL
  360. };
  361. static const struct attribute_group smsc47m1_group_fan1 = {
  362. .attrs = smsc47m1_attributes_fan1,
  363. };
  364. static struct attribute *smsc47m1_attributes_fan2[] = {
  365. &sensor_dev_attr_fan2_input.dev_attr.attr,
  366. &sensor_dev_attr_fan2_min.dev_attr.attr,
  367. &sensor_dev_attr_fan2_div.dev_attr.attr,
  368. &sensor_dev_attr_fan2_alarm.dev_attr.attr,
  369. NULL
  370. };
  371. static const struct attribute_group smsc47m1_group_fan2 = {
  372. .attrs = smsc47m1_attributes_fan2,
  373. };
  374. static struct attribute *smsc47m1_attributes_fan3[] = {
  375. &sensor_dev_attr_fan3_input.dev_attr.attr,
  376. &sensor_dev_attr_fan3_min.dev_attr.attr,
  377. &sensor_dev_attr_fan3_div.dev_attr.attr,
  378. &sensor_dev_attr_fan3_alarm.dev_attr.attr,
  379. NULL
  380. };
  381. static const struct attribute_group smsc47m1_group_fan3 = {
  382. .attrs = smsc47m1_attributes_fan3,
  383. };
  384. static struct attribute *smsc47m1_attributes_pwm1[] = {
  385. &sensor_dev_attr_pwm1.dev_attr.attr,
  386. &sensor_dev_attr_pwm1_enable.dev_attr.attr,
  387. NULL
  388. };
  389. static const struct attribute_group smsc47m1_group_pwm1 = {
  390. .attrs = smsc47m1_attributes_pwm1,
  391. };
  392. static struct attribute *smsc47m1_attributes_pwm2[] = {
  393. &sensor_dev_attr_pwm2.dev_attr.attr,
  394. &sensor_dev_attr_pwm2_enable.dev_attr.attr,
  395. NULL
  396. };
  397. static const struct attribute_group smsc47m1_group_pwm2 = {
  398. .attrs = smsc47m1_attributes_pwm2,
  399. };
  400. static struct attribute *smsc47m1_attributes_pwm3[] = {
  401. &sensor_dev_attr_pwm3.dev_attr.attr,
  402. &sensor_dev_attr_pwm3_enable.dev_attr.attr,
  403. NULL
  404. };
  405. static const struct attribute_group smsc47m1_group_pwm3 = {
  406. .attrs = smsc47m1_attributes_pwm3,
  407. };
  408. static struct attribute *smsc47m1_attributes[] = {
  409. &dev_attr_alarms.attr,
  410. &dev_attr_name.attr,
  411. NULL
  412. };
  413. static const struct attribute_group smsc47m1_group = {
  414. .attrs = smsc47m1_attributes,
  415. };
  416. static int __init smsc47m1_find(struct smsc47m1_sio_data *sio_data)
  417. {
  418. u8 val;
  419. unsigned short addr;
  420. superio_enter();
  421. val = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID);
  422. /*
  423. * SMSC LPC47M10x/LPC47M112/LPC47M13x (device id 0x59), LPC47M14x
  424. * (device id 0x5F) and LPC47B27x (device id 0x51) have fan control.
  425. * The LPC47M15x and LPC47M192 chips "with hardware monitoring block"
  426. * can do much more besides (device id 0x60).
  427. * The LPC47M997 is undocumented, but seems to be compatible with
  428. * the LPC47M192, and has the same device id.
  429. * The LPC47M292 (device id 0x6B) is somewhat compatible, but it
  430. * supports a 3rd fan, and the pin configuration registers are
  431. * unfortunately different.
  432. * The LPC47M233 has the same device id (0x6B) but is not compatible.
  433. * We check the high bit of the device revision register to
  434. * differentiate them.
  435. */
  436. switch (val) {
  437. case 0x51:
  438. pr_info("Found SMSC LPC47B27x\n");
  439. sio_data->type = smsc47m1;
  440. break;
  441. case 0x59:
  442. pr_info("Found SMSC LPC47M10x/LPC47M112/LPC47M13x\n");
  443. sio_data->type = smsc47m1;
  444. break;
  445. case 0x5F:
  446. pr_info("Found SMSC LPC47M14x\n");
  447. sio_data->type = smsc47m1;
  448. break;
  449. case 0x60:
  450. pr_info("Found SMSC LPC47M15x/LPC47M192/LPC47M997\n");
  451. sio_data->type = smsc47m1;
  452. break;
  453. case 0x6B:
  454. if (superio_inb(SUPERIO_REG_DEVREV) & 0x80) {
  455. pr_debug("Found SMSC LPC47M233, unsupported\n");
  456. superio_exit();
  457. return -ENODEV;
  458. }
  459. pr_info("Found SMSC LPC47M292\n");
  460. sio_data->type = smsc47m2;
  461. break;
  462. default:
  463. superio_exit();
  464. return -ENODEV;
  465. }
  466. superio_select();
  467. addr = (superio_inb(SUPERIO_REG_BASE) << 8)
  468. | superio_inb(SUPERIO_REG_BASE + 1);
  469. if (addr == 0) {
  470. pr_info("Device address not set, will not use\n");
  471. superio_exit();
  472. return -ENODEV;
  473. }
  474. /*
  475. * Enable only if address is set (needed at least on the
  476. * Compaq Presario S4000NX)
  477. */
  478. sio_data->activate = superio_inb(SUPERIO_REG_ACT);
  479. if ((sio_data->activate & 0x01) == 0) {
  480. pr_info("Enabling device\n");
  481. superio_outb(SUPERIO_REG_ACT, sio_data->activate | 0x01);
  482. }
  483. superio_exit();
  484. return addr;
  485. }
  486. /* Restore device to its initial state */
  487. static void smsc47m1_restore(const struct smsc47m1_sio_data *sio_data)
  488. {
  489. if ((sio_data->activate & 0x01) == 0) {
  490. superio_enter();
  491. superio_select();
  492. pr_info("Disabling device\n");
  493. superio_outb(SUPERIO_REG_ACT, sio_data->activate);
  494. superio_exit();
  495. }
  496. }
  497. #define CHECK 1
  498. #define REQUEST 2
  499. #define RELEASE 3
  500. /*
  501. * This function can be used to:
  502. * - test for resource conflicts with ACPI
  503. * - request the resources
  504. * - release the resources
  505. * We only allocate the I/O ports we really need, to minimize the risk of
  506. * conflicts with ACPI or with other drivers.
  507. */
  508. static int smsc47m1_handle_resources(unsigned short address, enum chips type,
  509. int action, struct device *dev)
  510. {
  511. static const u8 ports_m1[] = {
  512. /* register, region length */
  513. 0x04, 1,
  514. 0x33, 4,
  515. 0x56, 7,
  516. };
  517. static const u8 ports_m2[] = {
  518. /* register, region length */
  519. 0x04, 1,
  520. 0x09, 1,
  521. 0x2c, 2,
  522. 0x35, 4,
  523. 0x56, 7,
  524. 0x69, 4,
  525. };
  526. int i, ports_size, err;
  527. const u8 *ports;
  528. switch (type) {
  529. case smsc47m1:
  530. default:
  531. ports = ports_m1;
  532. ports_size = ARRAY_SIZE(ports_m1);
  533. break;
  534. case smsc47m2:
  535. ports = ports_m2;
  536. ports_size = ARRAY_SIZE(ports_m2);
  537. break;
  538. }
  539. for (i = 0; i + 1 < ports_size; i += 2) {
  540. unsigned short start = address + ports[i];
  541. unsigned short len = ports[i + 1];
  542. switch (action) {
  543. case CHECK:
  544. /* Only check for conflicts */
  545. err = acpi_check_region(start, len, DRVNAME);
  546. if (err)
  547. return err;
  548. break;
  549. case REQUEST:
  550. /* Request the resources */
  551. if (!request_region(start, len, DRVNAME)) {
  552. dev_err(dev, "Region 0x%hx-0x%hx already in "
  553. "use!\n", start, start + len);
  554. /* Undo all requests */
  555. for (i -= 2; i >= 0; i -= 2)
  556. release_region(address + ports[i],
  557. ports[i + 1]);
  558. return -EBUSY;
  559. }
  560. break;
  561. case RELEASE:
  562. /* Release the resources */
  563. release_region(start, len);
  564. break;
  565. }
  566. }
  567. return 0;
  568. }
  569. static void smsc47m1_remove_files(struct device *dev)
  570. {
  571. sysfs_remove_group(&dev->kobj, &smsc47m1_group);
  572. sysfs_remove_group(&dev->kobj, &smsc47m1_group_fan1);
  573. sysfs_remove_group(&dev->kobj, &smsc47m1_group_fan2);
  574. sysfs_remove_group(&dev->kobj, &smsc47m1_group_fan3);
  575. sysfs_remove_group(&dev->kobj, &smsc47m1_group_pwm1);
  576. sysfs_remove_group(&dev->kobj, &smsc47m1_group_pwm2);
  577. sysfs_remove_group(&dev->kobj, &smsc47m1_group_pwm3);
  578. }
  579. static int __init smsc47m1_probe(struct platform_device *pdev)
  580. {
  581. struct device *dev = &pdev->dev;
  582. struct smsc47m1_sio_data *sio_data = dev->platform_data;
  583. struct smsc47m1_data *data;
  584. struct resource *res;
  585. int err;
  586. int fan1, fan2, fan3, pwm1, pwm2, pwm3;
  587. static const char * const names[] = {
  588. "smsc47m1",
  589. "smsc47m2",
  590. };
  591. res = platform_get_resource(pdev, IORESOURCE_IO, 0);
  592. err = smsc47m1_handle_resources(res->start, sio_data->type,
  593. REQUEST, dev);
  594. if (err < 0)
  595. return err;
  596. data = kzalloc(sizeof(struct smsc47m1_data), GFP_KERNEL);
  597. if (!data) {
  598. err = -ENOMEM;
  599. goto error_release;
  600. }
  601. data->addr = res->start;
  602. data->type = sio_data->type;
  603. data->name = names[sio_data->type];
  604. mutex_init(&data->update_lock);
  605. platform_set_drvdata(pdev, data);
  606. /*
  607. * If no function is properly configured, there's no point in
  608. * actually registering the chip.
  609. */
  610. pwm1 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(0)) & 0x05)
  611. == 0x04;
  612. pwm2 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(1)) & 0x05)
  613. == 0x04;
  614. if (data->type == smsc47m2) {
  615. fan1 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN1)
  616. & 0x0d) == 0x09;
  617. fan2 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN2)
  618. & 0x0d) == 0x09;
  619. fan3 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN3)
  620. & 0x0d) == 0x0d;
  621. pwm3 = (smsc47m1_read_value(data, SMSC47M2_REG_PPIN3)
  622. & 0x0d) == 0x08;
  623. } else {
  624. fan1 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(0))
  625. & 0x05) == 0x05;
  626. fan2 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(1))
  627. & 0x05) == 0x05;
  628. fan3 = 0;
  629. pwm3 = 0;
  630. }
  631. if (!(fan1 || fan2 || fan3 || pwm1 || pwm2 || pwm3)) {
  632. dev_warn(dev, "Device not configured, will not use\n");
  633. err = -ENODEV;
  634. goto error_free;
  635. }
  636. /*
  637. * Some values (fan min, clock dividers, pwm registers) may be
  638. * needed before any update is triggered, so we better read them
  639. * at least once here. We don't usually do it that way, but in
  640. * this particular case, manually reading 5 registers out of 8
  641. * doesn't make much sense and we're better using the existing
  642. * function.
  643. */
  644. smsc47m1_update_device(dev, 1);
  645. /* Register sysfs hooks */
  646. if (fan1) {
  647. err = sysfs_create_group(&dev->kobj,
  648. &smsc47m1_group_fan1);
  649. if (err)
  650. goto error_remove_files;
  651. } else
  652. dev_dbg(dev, "Fan 1 not enabled by hardware, skipping\n");
  653. if (fan2) {
  654. err = sysfs_create_group(&dev->kobj,
  655. &smsc47m1_group_fan2);
  656. if (err)
  657. goto error_remove_files;
  658. } else
  659. dev_dbg(dev, "Fan 2 not enabled by hardware, skipping\n");
  660. if (fan3) {
  661. err = sysfs_create_group(&dev->kobj,
  662. &smsc47m1_group_fan3);
  663. if (err)
  664. goto error_remove_files;
  665. } else if (data->type == smsc47m2)
  666. dev_dbg(dev, "Fan 3 not enabled by hardware, skipping\n");
  667. if (pwm1) {
  668. err = sysfs_create_group(&dev->kobj,
  669. &smsc47m1_group_pwm1);
  670. if (err)
  671. goto error_remove_files;
  672. } else
  673. dev_dbg(dev, "PWM 1 not enabled by hardware, skipping\n");
  674. if (pwm2) {
  675. err = sysfs_create_group(&dev->kobj,
  676. &smsc47m1_group_pwm2);
  677. if (err)
  678. goto error_remove_files;
  679. } else
  680. dev_dbg(dev, "PWM 2 not enabled by hardware, skipping\n");
  681. if (pwm3) {
  682. err = sysfs_create_group(&dev->kobj,
  683. &smsc47m1_group_pwm3);
  684. if (err)
  685. goto error_remove_files;
  686. } else if (data->type == smsc47m2)
  687. dev_dbg(dev, "PWM 3 not enabled by hardware, skipping\n");
  688. err = sysfs_create_group(&dev->kobj, &smsc47m1_group);
  689. if (err)
  690. goto error_remove_files;
  691. data->hwmon_dev = hwmon_device_register(dev);
  692. if (IS_ERR(data->hwmon_dev)) {
  693. err = PTR_ERR(data->hwmon_dev);
  694. goto error_remove_files;
  695. }
  696. return 0;
  697. error_remove_files:
  698. smsc47m1_remove_files(dev);
  699. error_free:
  700. platform_set_drvdata(pdev, NULL);
  701. kfree(data);
  702. error_release:
  703. smsc47m1_handle_resources(res->start, sio_data->type, RELEASE, dev);
  704. return err;
  705. }
  706. static int __exit smsc47m1_remove(struct platform_device *pdev)
  707. {
  708. struct smsc47m1_data *data = platform_get_drvdata(pdev);
  709. struct resource *res;
  710. hwmon_device_unregister(data->hwmon_dev);
  711. smsc47m1_remove_files(&pdev->dev);
  712. res = platform_get_resource(pdev, IORESOURCE_IO, 0);
  713. smsc47m1_handle_resources(res->start, data->type, RELEASE, &pdev->dev);
  714. platform_set_drvdata(pdev, NULL);
  715. kfree(data);
  716. return 0;
  717. }
  718. static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
  719. int init)
  720. {
  721. struct smsc47m1_data *data = dev_get_drvdata(dev);
  722. mutex_lock(&data->update_lock);
  723. if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) {
  724. int i, fan_nr;
  725. fan_nr = data->type == smsc47m2 ? 3 : 2;
  726. for (i = 0; i < fan_nr; i++) {
  727. data->fan[i] = smsc47m1_read_value(data,
  728. SMSC47M1_REG_FAN[i]);
  729. data->fan_preload[i] = smsc47m1_read_value(data,
  730. SMSC47M1_REG_FAN_PRELOAD[i]);
  731. data->pwm[i] = smsc47m1_read_value(data,
  732. SMSC47M1_REG_PWM[i]);
  733. }
  734. i = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV);
  735. data->fan_div[0] = (i >> 4) & 0x03;
  736. data->fan_div[1] = i >> 6;
  737. data->alarms = smsc47m1_read_value(data,
  738. SMSC47M1_REG_ALARM) >> 6;
  739. /* Clear alarms if needed */
  740. if (data->alarms)
  741. smsc47m1_write_value(data, SMSC47M1_REG_ALARM, 0xC0);
  742. if (fan_nr >= 3) {
  743. data->fan_div[2] = (smsc47m1_read_value(data,
  744. SMSC47M2_REG_FANDIV3) >> 4) & 0x03;
  745. data->alarms |= (smsc47m1_read_value(data,
  746. SMSC47M2_REG_ALARM6) & 0x40) >> 4;
  747. /* Clear alarm if needed */
  748. if (data->alarms & 0x04)
  749. smsc47m1_write_value(data,
  750. SMSC47M2_REG_ALARM6,
  751. 0x40);
  752. }
  753. data->last_updated = jiffies;
  754. }
  755. mutex_unlock(&data->update_lock);
  756. return data;
  757. }
  758. static int __init smsc47m1_device_add(unsigned short address,
  759. const struct smsc47m1_sio_data *sio_data)
  760. {
  761. struct resource res = {
  762. .start = address,
  763. .end = address + SMSC_EXTENT - 1,
  764. .name = DRVNAME,
  765. .flags = IORESOURCE_IO,
  766. };
  767. int err;
  768. err = smsc47m1_handle_resources(address, sio_data->type, CHECK, NULL);
  769. if (err)
  770. goto exit;
  771. pdev = platform_device_alloc(DRVNAME, address);
  772. if (!pdev) {
  773. err = -ENOMEM;
  774. pr_err("Device allocation failed\n");
  775. goto exit;
  776. }
  777. err = platform_device_add_resources(pdev, &res, 1);
  778. if (err) {
  779. pr_err("Device resource addition failed (%d)\n", err);
  780. goto exit_device_put;
  781. }
  782. err = platform_device_add_data(pdev, sio_data,
  783. sizeof(struct smsc47m1_sio_data));
  784. if (err) {
  785. pr_err("Platform data allocation failed\n");
  786. goto exit_device_put;
  787. }
  788. err = platform_device_add(pdev);
  789. if (err) {
  790. pr_err("Device addition failed (%d)\n", err);
  791. goto exit_device_put;
  792. }
  793. return 0;
  794. exit_device_put:
  795. platform_device_put(pdev);
  796. exit:
  797. return err;
  798. }
  799. static int __init sm_smsc47m1_init(void)
  800. {
  801. int err;
  802. unsigned short address;
  803. struct smsc47m1_sio_data sio_data;
  804. err = smsc47m1_find(&sio_data);
  805. if (err < 0)
  806. return err;
  807. address = err;
  808. /* Sets global pdev as a side effect */
  809. err = smsc47m1_device_add(address, &sio_data);
  810. if (err)
  811. return err;
  812. err = platform_driver_probe(&smsc47m1_driver, smsc47m1_probe);
  813. if (err)
  814. goto exit_device;
  815. return 0;
  816. exit_device:
  817. platform_device_unregister(pdev);
  818. smsc47m1_restore(&sio_data);
  819. return err;
  820. }
  821. static void __exit sm_smsc47m1_exit(void)
  822. {
  823. platform_driver_unregister(&smsc47m1_driver);
  824. smsc47m1_restore(pdev->dev.platform_data);
  825. platform_device_unregister(pdev);
  826. }
  827. MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
  828. MODULE_DESCRIPTION("SMSC LPC47M1xx fan sensors driver");
  829. MODULE_LICENSE("GPL");
  830. module_init(sm_smsc47m1_init);
  831. module_exit(sm_smsc47m1_exit);