mcp9600.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * mcp9600.c - Support for Microchip MCP9600 thermocouple EMF converter
  4. *
  5. * Copyright (c) 2022 Andrew Hepp
  6. * Author: <andrew.hepp@ahepp.dev>
  7. */
  8. #include <linux/bitfield.h>
  9. #include <linux/bitops.h>
  10. #include <linux/bits.h>
  11. #include <linux/err.h>
  12. #include <linux/i2c.h>
  13. #include <linux/init.h>
  14. #include <linux/interrupt.h>
  15. #include <linux/irq.h>
  16. #include <linux/math.h>
  17. #include <linux/minmax.h>
  18. #include <linux/mod_devicetable.h>
  19. #include <linux/module.h>
  20. #include <linux/iio/events.h>
  21. #include <linux/iio/iio.h>
  22. /* MCP9600 registers */
  23. #define MCP9600_HOT_JUNCTION 0x0
  24. #define MCP9600_COLD_JUNCTION 0x2
  25. #define MCP9600_STATUS 0x4
  26. #define MCP9600_STATUS_ALERT(x) BIT(x)
  27. #define MCP9600_ALERT_CFG1 0x8
  28. #define MCP9600_ALERT_CFG(x) (MCP9600_ALERT_CFG1 + (x - 1))
  29. #define MCP9600_ALERT_CFG_ENABLE BIT(0)
  30. #define MCP9600_ALERT_CFG_ACTIVE_HIGH BIT(2)
  31. #define MCP9600_ALERT_CFG_FALLING BIT(3)
  32. #define MCP9600_ALERT_CFG_COLD_JUNCTION BIT(4)
  33. #define MCP9600_ALERT_HYSTERESIS1 0xc
  34. #define MCP9600_ALERT_HYSTERESIS(x) (MCP9600_ALERT_HYSTERESIS1 + (x - 1))
  35. #define MCP9600_ALERT_LIMIT1 0x10
  36. #define MCP9600_ALERT_LIMIT(x) (MCP9600_ALERT_LIMIT1 + (x - 1))
  37. #define MCP9600_ALERT_LIMIT_MASK GENMASK(15, 2)
  38. #define MCP9600_DEVICE_ID 0x20
  39. /* MCP9600 device id value */
  40. #define MCP9600_DEVICE_ID_MCP9600 0x40
  41. #define MCP9600_ALERT_COUNT 4
  42. #define MCP9600_MIN_TEMP_HOT_JUNCTION_MICRO -200000000
  43. #define MCP9600_MAX_TEMP_HOT_JUNCTION_MICRO 1800000000
  44. #define MCP9600_MIN_TEMP_COLD_JUNCTION_MICRO -40000000
  45. #define MCP9600_MAX_TEMP_COLD_JUNCTION_MICRO 125000000
  46. enum mcp9600_alert {
  47. MCP9600_ALERT1,
  48. MCP9600_ALERT2,
  49. MCP9600_ALERT3,
  50. MCP9600_ALERT4
  51. };
  52. static const char * const mcp9600_alert_name[MCP9600_ALERT_COUNT] = {
  53. [MCP9600_ALERT1] = "alert1",
  54. [MCP9600_ALERT2] = "alert2",
  55. [MCP9600_ALERT3] = "alert3",
  56. [MCP9600_ALERT4] = "alert4",
  57. };
  58. static const struct iio_event_spec mcp9600_events[] = {
  59. {
  60. .type = IIO_EV_TYPE_THRESH,
  61. .dir = IIO_EV_DIR_RISING,
  62. .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
  63. BIT(IIO_EV_INFO_VALUE) |
  64. BIT(IIO_EV_INFO_HYSTERESIS),
  65. },
  66. {
  67. .type = IIO_EV_TYPE_THRESH,
  68. .dir = IIO_EV_DIR_FALLING,
  69. .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
  70. BIT(IIO_EV_INFO_VALUE) |
  71. BIT(IIO_EV_INFO_HYSTERESIS),
  72. },
  73. };
  74. #define MCP9600_CHANNELS(hj_num_ev, hj_ev_spec_off, cj_num_ev, cj_ev_spec_off) \
  75. { \
  76. { \
  77. .type = IIO_TEMP, \
  78. .address = MCP9600_HOT_JUNCTION, \
  79. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
  80. BIT(IIO_CHAN_INFO_SCALE), \
  81. .event_spec = &mcp9600_events[hj_ev_spec_off], \
  82. .num_event_specs = hj_num_ev, \
  83. }, \
  84. { \
  85. .type = IIO_TEMP, \
  86. .address = MCP9600_COLD_JUNCTION, \
  87. .channel2 = IIO_MOD_TEMP_AMBIENT, \
  88. .modified = 1, \
  89. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
  90. BIT(IIO_CHAN_INFO_SCALE), \
  91. .event_spec = &mcp9600_events[cj_ev_spec_off], \
  92. .num_event_specs = cj_num_ev, \
  93. }, \
  94. }
  95. static const struct iio_chan_spec mcp9600_channels[][2] = {
  96. MCP9600_CHANNELS(0, 0, 0, 0), /* Alerts: - - - - */
  97. MCP9600_CHANNELS(1, 0, 0, 0), /* Alerts: 1 - - - */
  98. MCP9600_CHANNELS(1, 1, 0, 0), /* Alerts: - 2 - - */
  99. MCP9600_CHANNELS(2, 0, 0, 0), /* Alerts: 1 2 - - */
  100. MCP9600_CHANNELS(0, 0, 1, 0), /* Alerts: - - 3 - */
  101. MCP9600_CHANNELS(1, 0, 1, 0), /* Alerts: 1 - 3 - */
  102. MCP9600_CHANNELS(1, 1, 1, 0), /* Alerts: - 2 3 - */
  103. MCP9600_CHANNELS(2, 0, 1, 0), /* Alerts: 1 2 3 - */
  104. MCP9600_CHANNELS(0, 0, 1, 1), /* Alerts: - - - 4 */
  105. MCP9600_CHANNELS(1, 0, 1, 1), /* Alerts: 1 - - 4 */
  106. MCP9600_CHANNELS(1, 1, 1, 1), /* Alerts: - 2 - 4 */
  107. MCP9600_CHANNELS(2, 0, 1, 1), /* Alerts: 1 2 - 4 */
  108. MCP9600_CHANNELS(0, 0, 2, 0), /* Alerts: - - 3 4 */
  109. MCP9600_CHANNELS(1, 0, 2, 0), /* Alerts: 1 - 3 4 */
  110. MCP9600_CHANNELS(1, 1, 2, 0), /* Alerts: - 2 3 4 */
  111. MCP9600_CHANNELS(2, 0, 2, 0), /* Alerts: 1 2 3 4 */
  112. };
  113. struct mcp9600_data {
  114. struct i2c_client *client;
  115. };
  116. static int mcp9600_read(struct mcp9600_data *data,
  117. struct iio_chan_spec const *chan, int *val)
  118. {
  119. int ret;
  120. ret = i2c_smbus_read_word_swapped(data->client, chan->address);
  121. if (ret < 0)
  122. return ret;
  123. *val = sign_extend32(ret, 15);
  124. return 0;
  125. }
  126. static int mcp9600_read_raw(struct iio_dev *indio_dev,
  127. struct iio_chan_spec const *chan, int *val,
  128. int *val2, long mask)
  129. {
  130. struct mcp9600_data *data = iio_priv(indio_dev);
  131. int ret;
  132. switch (mask) {
  133. case IIO_CHAN_INFO_RAW:
  134. ret = mcp9600_read(data, chan, val);
  135. if (ret)
  136. return ret;
  137. return IIO_VAL_INT;
  138. case IIO_CHAN_INFO_SCALE:
  139. *val = 62;
  140. *val2 = 500000;
  141. return IIO_VAL_INT_PLUS_MICRO;
  142. default:
  143. return -EINVAL;
  144. }
  145. }
  146. static int mcp9600_get_alert_index(int channel2, enum iio_event_direction dir)
  147. {
  148. if (channel2 == IIO_MOD_TEMP_AMBIENT) {
  149. if (dir == IIO_EV_DIR_RISING)
  150. return MCP9600_ALERT3;
  151. else
  152. return MCP9600_ALERT4;
  153. } else {
  154. if (dir == IIO_EV_DIR_RISING)
  155. return MCP9600_ALERT1;
  156. else
  157. return MCP9600_ALERT2;
  158. }
  159. }
  160. static int mcp9600_read_event_config(struct iio_dev *indio_dev,
  161. const struct iio_chan_spec *chan,
  162. enum iio_event_type type,
  163. enum iio_event_direction dir)
  164. {
  165. struct mcp9600_data *data = iio_priv(indio_dev);
  166. struct i2c_client *client = data->client;
  167. int i, ret;
  168. i = mcp9600_get_alert_index(chan->channel2, dir);
  169. ret = i2c_smbus_read_byte_data(client, MCP9600_ALERT_CFG(i + 1));
  170. if (ret < 0)
  171. return ret;
  172. return FIELD_GET(MCP9600_ALERT_CFG_ENABLE, ret);
  173. }
  174. static int mcp9600_write_event_config(struct iio_dev *indio_dev,
  175. const struct iio_chan_spec *chan,
  176. enum iio_event_type type,
  177. enum iio_event_direction dir,
  178. int state)
  179. {
  180. struct mcp9600_data *data = iio_priv(indio_dev);
  181. struct i2c_client *client = data->client;
  182. int i, ret;
  183. i = mcp9600_get_alert_index(chan->channel2, dir);
  184. ret = i2c_smbus_read_byte_data(client, MCP9600_ALERT_CFG(i + 1));
  185. if (ret < 0)
  186. return ret;
  187. if (state)
  188. ret |= MCP9600_ALERT_CFG_ENABLE;
  189. else
  190. ret &= ~MCP9600_ALERT_CFG_ENABLE;
  191. return i2c_smbus_write_byte_data(client, MCP9600_ALERT_CFG(i + 1), ret);
  192. }
  193. static int mcp9600_read_thresh(struct iio_dev *indio_dev,
  194. const struct iio_chan_spec *chan,
  195. enum iio_event_type type,
  196. enum iio_event_direction dir,
  197. enum iio_event_info info, int *val, int *val2)
  198. {
  199. struct mcp9600_data *data = iio_priv(indio_dev);
  200. struct i2c_client *client = data->client;
  201. s32 ret;
  202. int i;
  203. i = mcp9600_get_alert_index(chan->channel2, dir);
  204. switch (info) {
  205. case IIO_EV_INFO_VALUE:
  206. ret = i2c_smbus_read_word_swapped(client, MCP9600_ALERT_LIMIT(i + 1));
  207. if (ret < 0)
  208. return ret;
  209. /*
  210. * Temperature is stored in two’s complement format in
  211. * bits(15:2), LSB is 0.25 degree celsius.
  212. */
  213. *val = sign_extend32(FIELD_GET(MCP9600_ALERT_LIMIT_MASK, ret), 13);
  214. *val2 = 4;
  215. return IIO_VAL_FRACTIONAL;
  216. case IIO_EV_INFO_HYSTERESIS:
  217. ret = i2c_smbus_read_byte_data(client, MCP9600_ALERT_HYSTERESIS(i + 1));
  218. if (ret < 0)
  219. return ret;
  220. *val = ret;
  221. return IIO_VAL_INT;
  222. default:
  223. return -EINVAL;
  224. }
  225. }
  226. static int mcp9600_write_thresh(struct iio_dev *indio_dev,
  227. const struct iio_chan_spec *chan,
  228. enum iio_event_type type,
  229. enum iio_event_direction dir,
  230. enum iio_event_info info, int val, int val2)
  231. {
  232. struct mcp9600_data *data = iio_priv(indio_dev);
  233. struct i2c_client *client = data->client;
  234. int s_val, i;
  235. s16 thresh;
  236. u8 hyst;
  237. i = mcp9600_get_alert_index(chan->channel2, dir);
  238. switch (info) {
  239. case IIO_EV_INFO_VALUE:
  240. /* Scale value to include decimal part into calculations */
  241. s_val = (val < 0) ? ((val * 1000000) - val2) :
  242. ((val * 1000000) + val2);
  243. if (chan->channel2 == IIO_MOD_TEMP_AMBIENT) {
  244. s_val = max(s_val, MCP9600_MIN_TEMP_COLD_JUNCTION_MICRO);
  245. s_val = min(s_val, MCP9600_MAX_TEMP_COLD_JUNCTION_MICRO);
  246. } else {
  247. s_val = max(s_val, MCP9600_MIN_TEMP_HOT_JUNCTION_MICRO);
  248. s_val = min(s_val, MCP9600_MAX_TEMP_HOT_JUNCTION_MICRO);
  249. }
  250. /*
  251. * Shift length 4 bits = 2(15:2) + 2(0.25 LSB), temperature is
  252. * stored in two’s complement format.
  253. */
  254. thresh = (s16)(s_val / (1000000 >> 4));
  255. return i2c_smbus_write_word_swapped(client,
  256. MCP9600_ALERT_LIMIT(i + 1),
  257. thresh);
  258. case IIO_EV_INFO_HYSTERESIS:
  259. hyst = min(abs(val), 255);
  260. return i2c_smbus_write_byte_data(client,
  261. MCP9600_ALERT_HYSTERESIS(i + 1),
  262. hyst);
  263. default:
  264. return -EINVAL;
  265. }
  266. }
  267. static const struct iio_info mcp9600_info = {
  268. .read_raw = mcp9600_read_raw,
  269. .read_event_config = mcp9600_read_event_config,
  270. .write_event_config = mcp9600_write_event_config,
  271. .read_event_value = mcp9600_read_thresh,
  272. .write_event_value = mcp9600_write_thresh,
  273. };
  274. static irqreturn_t mcp9600_alert_handler(void *private,
  275. enum mcp9600_alert alert,
  276. enum iio_modifier mod,
  277. enum iio_event_direction dir)
  278. {
  279. struct iio_dev *indio_dev = private;
  280. struct mcp9600_data *data = iio_priv(indio_dev);
  281. int ret;
  282. ret = i2c_smbus_read_byte_data(data->client, MCP9600_STATUS);
  283. if (ret < 0)
  284. return IRQ_HANDLED;
  285. if (!(ret & MCP9600_STATUS_ALERT(alert)))
  286. return IRQ_NONE;
  287. iio_push_event(indio_dev,
  288. IIO_MOD_EVENT_CODE(IIO_TEMP, 0, mod, IIO_EV_TYPE_THRESH,
  289. dir),
  290. iio_get_time_ns(indio_dev));
  291. return IRQ_HANDLED;
  292. }
  293. static irqreturn_t mcp9600_alert1_handler(int irq, void *private)
  294. {
  295. return mcp9600_alert_handler(private, MCP9600_ALERT1, IIO_NO_MOD,
  296. IIO_EV_DIR_RISING);
  297. }
  298. static irqreturn_t mcp9600_alert2_handler(int irq, void *private)
  299. {
  300. return mcp9600_alert_handler(private, MCP9600_ALERT2, IIO_NO_MOD,
  301. IIO_EV_DIR_FALLING);
  302. }
  303. static irqreturn_t mcp9600_alert3_handler(int irq, void *private)
  304. {
  305. return mcp9600_alert_handler(private, MCP9600_ALERT3,
  306. IIO_MOD_TEMP_AMBIENT, IIO_EV_DIR_RISING);
  307. }
  308. static irqreturn_t mcp9600_alert4_handler(int irq, void *private)
  309. {
  310. return mcp9600_alert_handler(private, MCP9600_ALERT4,
  311. IIO_MOD_TEMP_AMBIENT, IIO_EV_DIR_FALLING);
  312. }
  313. static irqreturn_t (*mcp9600_alert_handler_func[MCP9600_ALERT_COUNT]) (int, void *) = {
  314. mcp9600_alert1_handler,
  315. mcp9600_alert2_handler,
  316. mcp9600_alert3_handler,
  317. mcp9600_alert4_handler,
  318. };
  319. static int mcp9600_probe_alerts(struct iio_dev *indio_dev)
  320. {
  321. struct mcp9600_data *data = iio_priv(indio_dev);
  322. struct i2c_client *client = data->client;
  323. struct device *dev = &client->dev;
  324. struct fwnode_handle *fwnode = dev_fwnode(dev);
  325. unsigned int irq_type;
  326. int ret, irq, i;
  327. u8 val, ch_sel;
  328. /*
  329. * alert1: hot junction, rising temperature
  330. * alert2: hot junction, falling temperature
  331. * alert3: cold junction, rising temperature
  332. * alert4: cold junction, falling temperature
  333. */
  334. ch_sel = 0;
  335. for (i = 0; i < MCP9600_ALERT_COUNT; i++) {
  336. irq = fwnode_irq_get_byname(fwnode, mcp9600_alert_name[i]);
  337. if (irq <= 0)
  338. continue;
  339. val = 0;
  340. irq_type = irq_get_trigger_type(irq);
  341. if (irq_type == IRQ_TYPE_EDGE_RISING)
  342. val |= MCP9600_ALERT_CFG_ACTIVE_HIGH;
  343. if (i == MCP9600_ALERT2 || i == MCP9600_ALERT4)
  344. val |= MCP9600_ALERT_CFG_FALLING;
  345. if (i == MCP9600_ALERT3 || i == MCP9600_ALERT4)
  346. val |= MCP9600_ALERT_CFG_COLD_JUNCTION;
  347. ret = i2c_smbus_write_byte_data(client,
  348. MCP9600_ALERT_CFG(i + 1),
  349. val);
  350. if (ret < 0)
  351. return ret;
  352. ret = devm_request_threaded_irq(dev, irq, NULL,
  353. mcp9600_alert_handler_func[i],
  354. IRQF_ONESHOT, "mcp9600",
  355. indio_dev);
  356. if (ret)
  357. return ret;
  358. ch_sel |= BIT(i);
  359. }
  360. return ch_sel;
  361. }
  362. static int mcp9600_probe(struct i2c_client *client)
  363. {
  364. struct iio_dev *indio_dev;
  365. struct mcp9600_data *data;
  366. int ret, ch_sel;
  367. ret = i2c_smbus_read_byte_data(client, MCP9600_DEVICE_ID);
  368. if (ret < 0)
  369. return dev_err_probe(&client->dev, ret, "Failed to read device ID\n");
  370. if (ret != MCP9600_DEVICE_ID_MCP9600)
  371. dev_warn(&client->dev, "Expected ID %x, got %x\n",
  372. MCP9600_DEVICE_ID_MCP9600, ret);
  373. indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
  374. if (!indio_dev)
  375. return -ENOMEM;
  376. data = iio_priv(indio_dev);
  377. data->client = client;
  378. ch_sel = mcp9600_probe_alerts(indio_dev);
  379. if (ch_sel < 0)
  380. return ch_sel;
  381. indio_dev->info = &mcp9600_info;
  382. indio_dev->name = "mcp9600";
  383. indio_dev->modes = INDIO_DIRECT_MODE;
  384. indio_dev->channels = mcp9600_channels[ch_sel];
  385. indio_dev->num_channels = ARRAY_SIZE(mcp9600_channels[ch_sel]);
  386. return devm_iio_device_register(&client->dev, indio_dev);
  387. }
  388. static const struct i2c_device_id mcp9600_id[] = {
  389. { "mcp9600" },
  390. {}
  391. };
  392. MODULE_DEVICE_TABLE(i2c, mcp9600_id);
  393. static const struct of_device_id mcp9600_of_match[] = {
  394. { .compatible = "microchip,mcp9600" },
  395. {}
  396. };
  397. MODULE_DEVICE_TABLE(of, mcp9600_of_match);
  398. static struct i2c_driver mcp9600_driver = {
  399. .driver = {
  400. .name = "mcp9600",
  401. .of_match_table = mcp9600_of_match,
  402. },
  403. .probe = mcp9600_probe,
  404. .id_table = mcp9600_id
  405. };
  406. module_i2c_driver(mcp9600_driver);
  407. MODULE_AUTHOR("Dimitri Fedrau <dima.fedrau@gmail.com>");
  408. MODULE_AUTHOR("Andrew Hepp <andrew.hepp@ahepp.dev>");
  409. MODULE_DESCRIPTION("Microchip MCP9600 thermocouple EMF converter driver");
  410. MODULE_LICENSE("GPL");