mlxreg-hotplug.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. /*
  2. * Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved.
  3. * Copyright (c) 2016-2018 Vadim Pasternak <vadimp@mellanox.com>
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the names of the copyright holders nor the names of its
  14. * contributors may be used to endorse or promote products derived from
  15. * this software without specific prior written permission.
  16. *
  17. * Alternatively, this software may be distributed under the terms of the
  18. * GNU General Public License ("GPL") version 2 as published by the Free
  19. * Software Foundation.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  22. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  25. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  26. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  27. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  28. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  29. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  30. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  31. * POSSIBILITY OF SUCH DAMAGE.
  32. */
  33. #include <linux/bitops.h>
  34. #include <linux/device.h>
  35. #include <linux/hwmon.h>
  36. #include <linux/hwmon-sysfs.h>
  37. #include <linux/i2c.h>
  38. #include <linux/interrupt.h>
  39. #include <linux/module.h>
  40. #include <linux/of_device.h>
  41. #include <linux/platform_data/mlxreg.h>
  42. #include <linux/platform_device.h>
  43. #include <linux/spinlock.h>
  44. #include <linux/regmap.h>
  45. #include <linux/workqueue.h>
  46. /* Offset of event and mask registers from status register. */
  47. #define MLXREG_HOTPLUG_EVENT_OFF 1
  48. #define MLXREG_HOTPLUG_MASK_OFF 2
  49. #define MLXREG_HOTPLUG_AGGR_MASK_OFF 1
  50. /* ASIC health parameters. */
  51. #define MLXREG_HOTPLUG_HEALTH_MASK 0x02
  52. #define MLXREG_HOTPLUG_RST_CNTR 3
  53. #define MLXREG_HOTPLUG_ATTRS_MAX 24
  54. /**
  55. * struct mlxreg_hotplug_priv_data - platform private data:
  56. * @irq: platform device interrupt number;
  57. * @pdev: platform device;
  58. * @plat: platform data;
  59. * @dwork: delayed work template;
  60. * @lock: spin lock;
  61. * @hwmon: hwmon device;
  62. * @mlxreg_hotplug_attr: sysfs attributes array;
  63. * @mlxreg_hotplug_dev_attr: sysfs sensor device attribute array;
  64. * @group: sysfs attribute group;
  65. * @groups: list of sysfs attribute group for hwmon registration;
  66. * @cell: location of top aggregation interrupt register;
  67. * @mask: top aggregation interrupt common mask;
  68. * @aggr_cache: last value of aggregation register status;
  69. */
  70. struct mlxreg_hotplug_priv_data {
  71. int irq;
  72. struct device *dev;
  73. struct platform_device *pdev;
  74. struct mlxreg_hotplug_platform_data *plat;
  75. struct regmap *regmap;
  76. struct delayed_work dwork_irq;
  77. struct delayed_work dwork;
  78. spinlock_t lock; /* sync with interrupt */
  79. struct device *hwmon;
  80. struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1];
  81. struct sensor_device_attribute_2
  82. mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_MAX];
  83. struct attribute_group group;
  84. const struct attribute_group *groups[2];
  85. u32 cell;
  86. u32 mask;
  87. u32 aggr_cache;
  88. bool after_probe;
  89. };
  90. static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
  91. struct mlxreg_core_data *data)
  92. {
  93. struct mlxreg_core_hotplug_platform_data *pdata;
  94. /*
  95. * Return if adapter number is negative. It could be in case hotplug
  96. * event is not associated with hotplug device.
  97. */
  98. if (data->hpdev.nr < 0)
  99. return 0;
  100. pdata = dev_get_platdata(&priv->pdev->dev);
  101. data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr +
  102. pdata->shift_nr);
  103. if (!data->hpdev.adapter) {
  104. dev_err(priv->dev, "Failed to get adapter for bus %d\n",
  105. data->hpdev.nr + pdata->shift_nr);
  106. return -EFAULT;
  107. }
  108. data->hpdev.client = i2c_new_device(data->hpdev.adapter,
  109. data->hpdev.brdinfo);
  110. if (!data->hpdev.client) {
  111. dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
  112. data->hpdev.brdinfo->type, data->hpdev.nr +
  113. pdata->shift_nr, data->hpdev.brdinfo->addr);
  114. i2c_put_adapter(data->hpdev.adapter);
  115. data->hpdev.adapter = NULL;
  116. return -EFAULT;
  117. }
  118. return 0;
  119. }
  120. static void mlxreg_hotplug_device_destroy(struct mlxreg_core_data *data)
  121. {
  122. if (data->hpdev.client) {
  123. i2c_unregister_device(data->hpdev.client);
  124. data->hpdev.client = NULL;
  125. }
  126. if (data->hpdev.adapter) {
  127. i2c_put_adapter(data->hpdev.adapter);
  128. data->hpdev.adapter = NULL;
  129. }
  130. }
  131. static ssize_t mlxreg_hotplug_attr_show(struct device *dev,
  132. struct device_attribute *attr,
  133. char *buf)
  134. {
  135. struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(dev);
  136. struct mlxreg_core_hotplug_platform_data *pdata;
  137. int index = to_sensor_dev_attr_2(attr)->index;
  138. int nr = to_sensor_dev_attr_2(attr)->nr;
  139. struct mlxreg_core_item *item;
  140. struct mlxreg_core_data *data;
  141. u32 regval;
  142. int ret;
  143. pdata = dev_get_platdata(&priv->pdev->dev);
  144. item = pdata->items + nr;
  145. data = item->data + index;
  146. ret = regmap_read(priv->regmap, data->reg, &regval);
  147. if (ret)
  148. return ret;
  149. if (item->health) {
  150. regval &= data->mask;
  151. } else {
  152. /* Bit = 0 : functional if item->inversed is true. */
  153. if (item->inversed)
  154. regval = !(regval & data->mask);
  155. else
  156. regval = !!(regval & data->mask);
  157. }
  158. return sprintf(buf, "%u\n", regval);
  159. }
  160. #define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i]
  161. #define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i]
  162. static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
  163. {
  164. struct mlxreg_core_hotplug_platform_data *pdata;
  165. struct mlxreg_core_item *item;
  166. struct mlxreg_core_data *data;
  167. int num_attrs = 0, id = 0, i, j;
  168. pdata = dev_get_platdata(&priv->pdev->dev);
  169. item = pdata->items;
  170. /* Go over all kinds of items - psu, pwr, fan. */
  171. for (i = 0; i < pdata->counter; i++, item++) {
  172. num_attrs += item->count;
  173. data = item->data;
  174. /* Go over all units within the item. */
  175. for (j = 0; j < item->count; j++, data++, id++) {
  176. PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr;
  177. PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev,
  178. GFP_KERNEL,
  179. data->label);
  180. if (!PRIV_ATTR(id)->name) {
  181. dev_err(priv->dev, "Memory allocation failed for attr %d.\n",
  182. id);
  183. return -ENOMEM;
  184. }
  185. PRIV_DEV_ATTR(id).dev_attr.attr.name =
  186. PRIV_ATTR(id)->name;
  187. PRIV_DEV_ATTR(id).dev_attr.attr.mode = 0444;
  188. PRIV_DEV_ATTR(id).dev_attr.show =
  189. mlxreg_hotplug_attr_show;
  190. PRIV_DEV_ATTR(id).nr = i;
  191. PRIV_DEV_ATTR(id).index = j;
  192. sysfs_attr_init(&PRIV_DEV_ATTR(id).dev_attr.attr);
  193. }
  194. }
  195. priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs *
  196. sizeof(struct attribute *),
  197. GFP_KERNEL);
  198. if (!priv->group.attrs)
  199. return -ENOMEM;
  200. priv->group.attrs = priv->mlxreg_hotplug_attr;
  201. priv->groups[0] = &priv->group;
  202. priv->groups[1] = NULL;
  203. return 0;
  204. }
  205. static void
  206. mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv,
  207. struct mlxreg_core_item *item)
  208. {
  209. struct mlxreg_core_data *data;
  210. u32 asserted, regval, bit;
  211. int ret;
  212. /*
  213. * Validate if item related to received signal type is valid.
  214. * It should never happen, excepted the situation when some
  215. * piece of hardware is broken. In such situation just produce
  216. * error message and return. Caller must continue to handle the
  217. * signals from other devices if any.
  218. */
  219. if (unlikely(!item)) {
  220. dev_err(priv->dev, "False signal: at offset:mask 0x%02x:0x%02x.\n",
  221. item->reg, item->mask);
  222. return;
  223. }
  224. /* Mask event. */
  225. ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
  226. 0);
  227. if (ret)
  228. goto out;
  229. /* Read status. */
  230. ret = regmap_read(priv->regmap, item->reg, &regval);
  231. if (ret)
  232. goto out;
  233. /* Set asserted bits and save last status. */
  234. regval &= item->mask;
  235. asserted = item->cache ^ regval;
  236. item->cache = regval;
  237. for_each_set_bit(bit, (unsigned long *)&asserted, 8) {
  238. data = item->data + bit;
  239. if (regval & BIT(bit)) {
  240. if (item->inversed)
  241. mlxreg_hotplug_device_destroy(data);
  242. else
  243. mlxreg_hotplug_device_create(priv, data);
  244. } else {
  245. if (item->inversed)
  246. mlxreg_hotplug_device_create(priv, data);
  247. else
  248. mlxreg_hotplug_device_destroy(data);
  249. }
  250. }
  251. /* Acknowledge event. */
  252. ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF,
  253. 0);
  254. if (ret)
  255. goto out;
  256. /* Unmask event. */
  257. ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
  258. item->mask);
  259. out:
  260. if (ret)
  261. dev_err(priv->dev, "Failed to complete workqueue.\n");
  262. }
  263. static void
  264. mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv,
  265. struct mlxreg_core_item *item)
  266. {
  267. struct mlxreg_core_data *data = item->data;
  268. u32 regval;
  269. int i, ret = 0;
  270. for (i = 0; i < item->count; i++, data++) {
  271. /* Mask event. */
  272. ret = regmap_write(priv->regmap, data->reg +
  273. MLXREG_HOTPLUG_MASK_OFF, 0);
  274. if (ret)
  275. goto out;
  276. /* Read status. */
  277. ret = regmap_read(priv->regmap, data->reg, &regval);
  278. if (ret)
  279. goto out;
  280. regval &= data->mask;
  281. item->cache = regval;
  282. if (regval == MLXREG_HOTPLUG_HEALTH_MASK) {
  283. if ((data->health_cntr++ == MLXREG_HOTPLUG_RST_CNTR) ||
  284. !priv->after_probe) {
  285. mlxreg_hotplug_device_create(priv, data);
  286. data->attached = true;
  287. }
  288. } else {
  289. if (data->attached) {
  290. mlxreg_hotplug_device_destroy(data);
  291. data->attached = false;
  292. data->health_cntr = 0;
  293. }
  294. }
  295. /* Acknowledge event. */
  296. ret = regmap_write(priv->regmap, data->reg +
  297. MLXREG_HOTPLUG_EVENT_OFF, 0);
  298. if (ret)
  299. goto out;
  300. /* Unmask event. */
  301. ret = regmap_write(priv->regmap, data->reg +
  302. MLXREG_HOTPLUG_MASK_OFF, data->mask);
  303. if (ret)
  304. goto out;
  305. }
  306. out:
  307. if (ret)
  308. dev_err(priv->dev, "Failed to complete workqueue.\n");
  309. }
  310. /*
  311. * mlxreg_hotplug_work_handler - performs traversing of device interrupt
  312. * registers according to the below hierarchy schema:
  313. *
  314. * Aggregation registers (status/mask)
  315. * PSU registers: *---*
  316. * *-----------------* | |
  317. * |status/event/mask|-----> | * |
  318. * *-----------------* | |
  319. * Power registers: | |
  320. * *-----------------* | |
  321. * |status/event/mask|-----> | * |
  322. * *-----------------* | |
  323. * FAN registers: | |--> CPU
  324. * *-----------------* | |
  325. * |status/event/mask|-----> | * |
  326. * *-----------------* | |
  327. * ASIC registers: | |
  328. * *-----------------* | |
  329. * |status/event/mask|-----> | * |
  330. * *-----------------* | |
  331. * *---*
  332. *
  333. * In case some system changed are detected: FAN in/out, PSU in/out, power
  334. * cable attached/detached, ASIC health good/bad, relevant device is created
  335. * or destroyed.
  336. */
  337. static void mlxreg_hotplug_work_handler(struct work_struct *work)
  338. {
  339. struct mlxreg_core_hotplug_platform_data *pdata;
  340. struct mlxreg_hotplug_priv_data *priv;
  341. struct mlxreg_core_item *item;
  342. u32 regval, aggr_asserted;
  343. unsigned long flags;
  344. int i, ret;
  345. priv = container_of(work, struct mlxreg_hotplug_priv_data,
  346. dwork_irq.work);
  347. pdata = dev_get_platdata(&priv->pdev->dev);
  348. item = pdata->items;
  349. /* Mask aggregation event. */
  350. ret = regmap_write(priv->regmap, pdata->cell +
  351. MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
  352. if (ret < 0)
  353. goto out;
  354. /* Read aggregation status. */
  355. ret = regmap_read(priv->regmap, pdata->cell, &regval);
  356. if (ret)
  357. goto out;
  358. regval &= pdata->mask;
  359. aggr_asserted = priv->aggr_cache ^ regval;
  360. priv->aggr_cache = regval;
  361. /* Handle topology and health configuration changes. */
  362. for (i = 0; i < pdata->counter; i++, item++) {
  363. if (aggr_asserted & item->aggr_mask) {
  364. if (item->health)
  365. mlxreg_hotplug_health_work_helper(priv, item);
  366. else
  367. mlxreg_hotplug_work_helper(priv, item);
  368. }
  369. }
  370. if (aggr_asserted) {
  371. spin_lock_irqsave(&priv->lock, flags);
  372. /*
  373. * It is possible, that some signals have been inserted, while
  374. * interrupt has been masked by mlxreg_hotplug_work_handler.
  375. * In this case such signals will be missed. In order to handle
  376. * these signals delayed work is canceled and work task
  377. * re-scheduled for immediate execution. It allows to handle
  378. * missed signals, if any. In other case work handler just
  379. * validates that no new signals have been received during
  380. * masking.
  381. */
  382. cancel_delayed_work(&priv->dwork_irq);
  383. schedule_delayed_work(&priv->dwork_irq, 0);
  384. spin_unlock_irqrestore(&priv->lock, flags);
  385. return;
  386. }
  387. /* Unmask aggregation event (no need acknowledge). */
  388. ret = regmap_write(priv->regmap, pdata->cell +
  389. MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
  390. out:
  391. if (ret)
  392. dev_err(priv->dev, "Failed to complete workqueue.\n");
  393. }
  394. static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv)
  395. {
  396. struct mlxreg_core_hotplug_platform_data *pdata;
  397. struct mlxreg_core_item *item;
  398. int i, ret;
  399. pdata = dev_get_platdata(&priv->pdev->dev);
  400. item = pdata->items;
  401. for (i = 0; i < pdata->counter; i++, item++) {
  402. /* Clear group presense event. */
  403. ret = regmap_write(priv->regmap, item->reg +
  404. MLXREG_HOTPLUG_EVENT_OFF, 0);
  405. if (ret)
  406. goto out;
  407. /* Set group initial status as mask and unmask group event. */
  408. if (item->inversed) {
  409. item->cache = item->mask;
  410. ret = regmap_write(priv->regmap, item->reg +
  411. MLXREG_HOTPLUG_MASK_OFF,
  412. item->mask);
  413. if (ret)
  414. goto out;
  415. }
  416. }
  417. /* Keep aggregation initial status as zero and unmask events. */
  418. ret = regmap_write(priv->regmap, pdata->cell +
  419. MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
  420. if (ret)
  421. goto out;
  422. /* Keep low aggregation initial status as zero and unmask events. */
  423. if (pdata->cell_low) {
  424. ret = regmap_write(priv->regmap, pdata->cell_low +
  425. MLXREG_HOTPLUG_AGGR_MASK_OFF,
  426. pdata->mask_low);
  427. if (ret)
  428. goto out;
  429. }
  430. /* Invoke work handler for initializing hot plug devices setting. */
  431. mlxreg_hotplug_work_handler(&priv->dwork_irq.work);
  432. out:
  433. if (ret)
  434. dev_err(priv->dev, "Failed to set interrupts.\n");
  435. enable_irq(priv->irq);
  436. return ret;
  437. }
  438. static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv)
  439. {
  440. struct mlxreg_core_hotplug_platform_data *pdata;
  441. struct mlxreg_core_item *item;
  442. struct mlxreg_core_data *data;
  443. int count, i, j;
  444. pdata = dev_get_platdata(&priv->pdev->dev);
  445. item = pdata->items;
  446. disable_irq(priv->irq);
  447. cancel_delayed_work_sync(&priv->dwork_irq);
  448. /* Mask low aggregation event, if defined. */
  449. if (pdata->cell_low)
  450. regmap_write(priv->regmap, pdata->cell_low +
  451. MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
  452. /* Mask aggregation event. */
  453. regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF,
  454. 0);
  455. /* Clear topology configurations. */
  456. for (i = 0; i < pdata->counter; i++, item++) {
  457. data = item->data;
  458. /* Mask group presense event. */
  459. regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF,
  460. 0);
  461. /* Clear group presense event. */
  462. regmap_write(priv->regmap, data->reg +
  463. MLXREG_HOTPLUG_EVENT_OFF, 0);
  464. /* Remove all the attached devices in group. */
  465. count = item->count;
  466. for (j = 0; j < count; j++, data++)
  467. mlxreg_hotplug_device_destroy(data);
  468. }
  469. }
  470. static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev)
  471. {
  472. struct mlxreg_hotplug_priv_data *priv;
  473. priv = (struct mlxreg_hotplug_priv_data *)dev;
  474. /* Schedule work task for immediate execution.*/
  475. schedule_delayed_work(&priv->dwork_irq, 0);
  476. return IRQ_HANDLED;
  477. }
  478. static int mlxreg_hotplug_probe(struct platform_device *pdev)
  479. {
  480. struct mlxreg_core_hotplug_platform_data *pdata;
  481. struct mlxreg_hotplug_priv_data *priv;
  482. struct i2c_adapter *deferred_adap;
  483. int err;
  484. pdata = dev_get_platdata(&pdev->dev);
  485. if (!pdata) {
  486. dev_err(&pdev->dev, "Failed to get platform data.\n");
  487. return -EINVAL;
  488. }
  489. /* Defer probing if the necessary adapter is not configured yet. */
  490. deferred_adap = i2c_get_adapter(pdata->deferred_nr);
  491. if (!deferred_adap)
  492. return -EPROBE_DEFER;
  493. i2c_put_adapter(deferred_adap);
  494. priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
  495. if (!priv)
  496. return -ENOMEM;
  497. if (pdata->irq) {
  498. priv->irq = pdata->irq;
  499. } else {
  500. priv->irq = platform_get_irq(pdev, 0);
  501. if (priv->irq < 0) {
  502. dev_err(&pdev->dev, "Failed to get platform irq: %d\n",
  503. priv->irq);
  504. return priv->irq;
  505. }
  506. }
  507. priv->regmap = pdata->regmap;
  508. priv->dev = pdev->dev.parent;
  509. priv->pdev = pdev;
  510. err = devm_request_irq(&pdev->dev, priv->irq,
  511. mlxreg_hotplug_irq_handler, IRQF_TRIGGER_FALLING
  512. | IRQF_SHARED, "mlxreg-hotplug", priv);
  513. if (err) {
  514. dev_err(&pdev->dev, "Failed to request irq: %d\n", err);
  515. return err;
  516. }
  517. disable_irq(priv->irq);
  518. spin_lock_init(&priv->lock);
  519. INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler);
  520. /* Perform initial interrupts setup. */
  521. mlxreg_hotplug_set_irq(priv);
  522. priv->after_probe = true;
  523. dev_set_drvdata(&pdev->dev, priv);
  524. err = mlxreg_hotplug_attr_init(priv);
  525. if (err) {
  526. dev_err(&pdev->dev, "Failed to allocate attributes: %d\n",
  527. err);
  528. return err;
  529. }
  530. priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
  531. "mlxreg_hotplug", priv, priv->groups);
  532. if (IS_ERR(priv->hwmon)) {
  533. dev_err(&pdev->dev, "Failed to register hwmon device %ld\n",
  534. PTR_ERR(priv->hwmon));
  535. return PTR_ERR(priv->hwmon);
  536. }
  537. return 0;
  538. }
  539. static int mlxreg_hotplug_remove(struct platform_device *pdev)
  540. {
  541. struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev);
  542. /* Clean interrupts setup. */
  543. mlxreg_hotplug_unset_irq(priv);
  544. return 0;
  545. }
  546. static struct platform_driver mlxreg_hotplug_driver = {
  547. .driver = {
  548. .name = "mlxreg-hotplug",
  549. },
  550. .probe = mlxreg_hotplug_probe,
  551. .remove = mlxreg_hotplug_remove,
  552. };
  553. module_platform_driver(mlxreg_hotplug_driver);
  554. MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
  555. MODULE_DESCRIPTION("Mellanox regmap hotplug platform driver");
  556. MODULE_LICENSE("Dual BSD/GPL");
  557. MODULE_ALIAS("platform:mlxreg-hotplug");