mlxreg-hotplug.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  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 good health mask. */
  51. #define MLXREG_HOTPLUG_GOOD_HEALTH_MASK 0x02
  52. #define MLXREG_HOTPLUG_ATTRS_MAX 24
  53. #define MLXREG_HOTPLUG_NOT_ASSERT 3
  54. /**
  55. * struct mlxreg_hotplug_priv_data - platform private data:
  56. * @irq: platform device interrupt number;
  57. * @dev: basic device;
  58. * @pdev: platform device;
  59. * @plat: platform data;
  60. * @regmap: register map handle;
  61. * @dwork_irq: delayed work template;
  62. * @lock: spin lock;
  63. * @hwmon: hwmon device;
  64. * @mlxreg_hotplug_attr: sysfs attributes array;
  65. * @mlxreg_hotplug_dev_attr: sysfs sensor device attribute array;
  66. * @group: sysfs attribute group;
  67. * @groups: list of sysfs attribute group for hwmon registration;
  68. * @cell: location of top aggregation interrupt register;
  69. * @mask: top aggregation interrupt common mask;
  70. * @aggr_cache: last value of aggregation register status;
  71. * @after_probe: flag indication probing completion;
  72. * @not_asserted: number of entries in workqueue with no signal assertion;
  73. */
  74. struct mlxreg_hotplug_priv_data {
  75. int irq;
  76. struct device *dev;
  77. struct platform_device *pdev;
  78. struct mlxreg_hotplug_platform_data *plat;
  79. struct regmap *regmap;
  80. struct delayed_work dwork_irq;
  81. spinlock_t lock; /* sync with interrupt */
  82. struct device *hwmon;
  83. struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1];
  84. struct sensor_device_attribute_2
  85. mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_MAX];
  86. struct attribute_group group;
  87. const struct attribute_group *groups[2];
  88. u32 cell;
  89. u32 mask;
  90. u32 aggr_cache;
  91. bool after_probe;
  92. u8 not_asserted;
  93. };
  94. static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
  95. struct mlxreg_core_data *data)
  96. {
  97. struct mlxreg_core_hotplug_platform_data *pdata;
  98. /* Notify user by sending hwmon uevent. */
  99. kobject_uevent(&priv->hwmon->kobj, KOBJ_CHANGE);
  100. /*
  101. * Return if adapter number is negative. It could be in case hotplug
  102. * event is not associated with hotplug device.
  103. */
  104. if (data->hpdev.nr < 0)
  105. return 0;
  106. pdata = dev_get_platdata(&priv->pdev->dev);
  107. data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr +
  108. pdata->shift_nr);
  109. if (!data->hpdev.adapter) {
  110. dev_err(priv->dev, "Failed to get adapter for bus %d\n",
  111. data->hpdev.nr + pdata->shift_nr);
  112. return -EFAULT;
  113. }
  114. data->hpdev.client = i2c_new_device(data->hpdev.adapter,
  115. data->hpdev.brdinfo);
  116. if (!data->hpdev.client) {
  117. dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
  118. data->hpdev.brdinfo->type, data->hpdev.nr +
  119. pdata->shift_nr, data->hpdev.brdinfo->addr);
  120. i2c_put_adapter(data->hpdev.adapter);
  121. data->hpdev.adapter = NULL;
  122. return -EFAULT;
  123. }
  124. return 0;
  125. }
  126. static void
  127. mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_priv_data *priv,
  128. struct mlxreg_core_data *data)
  129. {
  130. /* Notify user by sending hwmon uevent. */
  131. kobject_uevent(&priv->hwmon->kobj, KOBJ_CHANGE);
  132. if (data->hpdev.client) {
  133. i2c_unregister_device(data->hpdev.client);
  134. data->hpdev.client = NULL;
  135. }
  136. if (data->hpdev.adapter) {
  137. i2c_put_adapter(data->hpdev.adapter);
  138. data->hpdev.adapter = NULL;
  139. }
  140. }
  141. static ssize_t mlxreg_hotplug_attr_show(struct device *dev,
  142. struct device_attribute *attr,
  143. char *buf)
  144. {
  145. struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(dev);
  146. struct mlxreg_core_hotplug_platform_data *pdata;
  147. int index = to_sensor_dev_attr_2(attr)->index;
  148. int nr = to_sensor_dev_attr_2(attr)->nr;
  149. struct mlxreg_core_item *item;
  150. struct mlxreg_core_data *data;
  151. u32 regval;
  152. int ret;
  153. pdata = dev_get_platdata(&priv->pdev->dev);
  154. item = pdata->items + nr;
  155. data = item->data + index;
  156. ret = regmap_read(priv->regmap, data->reg, &regval);
  157. if (ret)
  158. return ret;
  159. if (item->health) {
  160. regval &= data->mask;
  161. } else {
  162. /* Bit = 0 : functional if item->inversed is true. */
  163. if (item->inversed)
  164. regval = !(regval & data->mask);
  165. else
  166. regval = !!(regval & data->mask);
  167. }
  168. return sprintf(buf, "%u\n", regval);
  169. }
  170. #define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i]
  171. #define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i]
  172. static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
  173. {
  174. struct mlxreg_core_hotplug_platform_data *pdata;
  175. struct mlxreg_core_item *item;
  176. struct mlxreg_core_data *data;
  177. int num_attrs = 0, id = 0, i, j;
  178. pdata = dev_get_platdata(&priv->pdev->dev);
  179. item = pdata->items;
  180. /* Go over all kinds of items - psu, pwr, fan. */
  181. for (i = 0; i < pdata->counter; i++, item++) {
  182. num_attrs += item->count;
  183. data = item->data;
  184. /* Go over all units within the item. */
  185. for (j = 0; j < item->count; j++, data++, id++) {
  186. PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr;
  187. PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev,
  188. GFP_KERNEL,
  189. data->label);
  190. if (!PRIV_ATTR(id)->name) {
  191. dev_err(priv->dev, "Memory allocation failed for attr %d.\n",
  192. id);
  193. return -ENOMEM;
  194. }
  195. PRIV_DEV_ATTR(id).dev_attr.attr.name =
  196. PRIV_ATTR(id)->name;
  197. PRIV_DEV_ATTR(id).dev_attr.attr.mode = 0444;
  198. PRIV_DEV_ATTR(id).dev_attr.show =
  199. mlxreg_hotplug_attr_show;
  200. PRIV_DEV_ATTR(id).nr = i;
  201. PRIV_DEV_ATTR(id).index = j;
  202. sysfs_attr_init(&PRIV_DEV_ATTR(id).dev_attr.attr);
  203. }
  204. }
  205. priv->group.attrs = devm_kcalloc(&priv->pdev->dev,
  206. num_attrs,
  207. sizeof(struct attribute *),
  208. GFP_KERNEL);
  209. if (!priv->group.attrs)
  210. return -ENOMEM;
  211. priv->group.attrs = priv->mlxreg_hotplug_attr;
  212. priv->groups[0] = &priv->group;
  213. priv->groups[1] = NULL;
  214. return 0;
  215. }
  216. static void
  217. mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv,
  218. struct mlxreg_core_item *item)
  219. {
  220. struct mlxreg_core_data *data;
  221. unsigned long asserted;
  222. u32 regval, bit;
  223. int ret;
  224. /*
  225. * Validate if item related to received signal type is valid.
  226. * It should never happen, excepted the situation when some
  227. * piece of hardware is broken. In such situation just produce
  228. * error message and return. Caller must continue to handle the
  229. * signals from other devices if any.
  230. */
  231. if (unlikely(!item)) {
  232. dev_err(priv->dev, "False signal: at offset:mask 0x%02x:0x%02x.\n",
  233. item->reg, item->mask);
  234. return;
  235. }
  236. /* Mask event. */
  237. ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
  238. 0);
  239. if (ret)
  240. goto out;
  241. /* Read status. */
  242. ret = regmap_read(priv->regmap, item->reg, &regval);
  243. if (ret)
  244. goto out;
  245. /* Set asserted bits and save last status. */
  246. regval &= item->mask;
  247. asserted = item->cache ^ regval;
  248. item->cache = regval;
  249. for_each_set_bit(bit, &asserted, 8) {
  250. data = item->data + bit;
  251. if (regval & BIT(bit)) {
  252. if (item->inversed)
  253. mlxreg_hotplug_device_destroy(priv, data);
  254. else
  255. mlxreg_hotplug_device_create(priv, data);
  256. } else {
  257. if (item->inversed)
  258. mlxreg_hotplug_device_create(priv, data);
  259. else
  260. mlxreg_hotplug_device_destroy(priv, data);
  261. }
  262. }
  263. /* Acknowledge event. */
  264. ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF,
  265. 0);
  266. if (ret)
  267. goto out;
  268. /* Unmask event. */
  269. ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
  270. item->mask);
  271. out:
  272. if (ret)
  273. dev_err(priv->dev, "Failed to complete workqueue.\n");
  274. }
  275. static void
  276. mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv,
  277. struct mlxreg_core_item *item)
  278. {
  279. struct mlxreg_core_data *data = item->data;
  280. u32 regval;
  281. int i, ret = 0;
  282. for (i = 0; i < item->count; i++, data++) {
  283. /* Mask event. */
  284. ret = regmap_write(priv->regmap, data->reg +
  285. MLXREG_HOTPLUG_MASK_OFF, 0);
  286. if (ret)
  287. goto out;
  288. /* Read status. */
  289. ret = regmap_read(priv->regmap, data->reg, &regval);
  290. if (ret)
  291. goto out;
  292. regval &= data->mask;
  293. if (item->cache == regval)
  294. goto ack_event;
  295. /*
  296. * ASIC health indication is provided through two bits. Bits
  297. * value 0x2 indicates that ASIC reached the good health, value
  298. * 0x0 indicates ASIC the bad health or dormant state and value
  299. * 0x3 indicates the booting state. During ASIC reset it should
  300. * pass the following states: dormant -> booting -> good.
  301. */
  302. if (regval == MLXREG_HOTPLUG_GOOD_HEALTH_MASK) {
  303. if (!data->attached) {
  304. /*
  305. * ASIC is in steady state. Connect associated
  306. * device, if configured.
  307. */
  308. mlxreg_hotplug_device_create(priv, data);
  309. data->attached = true;
  310. }
  311. } else {
  312. if (data->attached) {
  313. /*
  314. * ASIC health is failed after ASIC has been
  315. * in steady state. Disconnect associated
  316. * device, if it has been connected.
  317. */
  318. mlxreg_hotplug_device_destroy(priv, data);
  319. data->attached = false;
  320. data->health_cntr = 0;
  321. }
  322. }
  323. item->cache = regval;
  324. ack_event:
  325. /* Acknowledge event. */
  326. ret = regmap_write(priv->regmap, data->reg +
  327. MLXREG_HOTPLUG_EVENT_OFF, 0);
  328. if (ret)
  329. goto out;
  330. /* Unmask event. */
  331. ret = regmap_write(priv->regmap, data->reg +
  332. MLXREG_HOTPLUG_MASK_OFF, data->mask);
  333. if (ret)
  334. goto out;
  335. }
  336. out:
  337. if (ret)
  338. dev_err(priv->dev, "Failed to complete workqueue.\n");
  339. }
  340. /*
  341. * mlxreg_hotplug_work_handler - performs traversing of device interrupt
  342. * registers according to the below hierarchy schema:
  343. *
  344. * Aggregation registers (status/mask)
  345. * PSU registers: *---*
  346. * *-----------------* | |
  347. * |status/event/mask|-----> | * |
  348. * *-----------------* | |
  349. * Power registers: | |
  350. * *-----------------* | |
  351. * |status/event/mask|-----> | * |
  352. * *-----------------* | |
  353. * FAN registers: | |--> CPU
  354. * *-----------------* | |
  355. * |status/event/mask|-----> | * |
  356. * *-----------------* | |
  357. * ASIC registers: | |
  358. * *-----------------* | |
  359. * |status/event/mask|-----> | * |
  360. * *-----------------* | |
  361. * *---*
  362. *
  363. * In case some system changed are detected: FAN in/out, PSU in/out, power
  364. * cable attached/detached, ASIC health good/bad, relevant device is created
  365. * or destroyed.
  366. */
  367. static void mlxreg_hotplug_work_handler(struct work_struct *work)
  368. {
  369. struct mlxreg_core_hotplug_platform_data *pdata;
  370. struct mlxreg_hotplug_priv_data *priv;
  371. struct mlxreg_core_item *item;
  372. u32 regval, aggr_asserted;
  373. unsigned long flags;
  374. int i, ret;
  375. priv = container_of(work, struct mlxreg_hotplug_priv_data,
  376. dwork_irq.work);
  377. pdata = dev_get_platdata(&priv->pdev->dev);
  378. item = pdata->items;
  379. /* Mask aggregation event. */
  380. ret = regmap_write(priv->regmap, pdata->cell +
  381. MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
  382. if (ret < 0)
  383. goto out;
  384. /* Read aggregation status. */
  385. ret = regmap_read(priv->regmap, pdata->cell, &regval);
  386. if (ret)
  387. goto out;
  388. regval &= pdata->mask;
  389. aggr_asserted = priv->aggr_cache ^ regval;
  390. priv->aggr_cache = regval;
  391. /*
  392. * Handler is invoked, but no assertion is detected at top aggregation
  393. * status level. Set aggr_asserted to mask value to allow handler extra
  394. * run over all relevant signals to recover any missed signal.
  395. */
  396. if (priv->not_asserted == MLXREG_HOTPLUG_NOT_ASSERT) {
  397. priv->not_asserted = 0;
  398. aggr_asserted = pdata->mask;
  399. }
  400. if (!aggr_asserted)
  401. goto unmask_event;
  402. /* Handle topology and health configuration changes. */
  403. for (i = 0; i < pdata->counter; i++, item++) {
  404. if (aggr_asserted & item->aggr_mask) {
  405. if (item->health)
  406. mlxreg_hotplug_health_work_helper(priv, item);
  407. else
  408. mlxreg_hotplug_work_helper(priv, item);
  409. }
  410. }
  411. spin_lock_irqsave(&priv->lock, flags);
  412. /*
  413. * It is possible, that some signals have been inserted, while
  414. * interrupt has been masked by mlxreg_hotplug_work_handler. In this
  415. * case such signals will be missed. In order to handle these signals
  416. * delayed work is canceled and work task re-scheduled for immediate
  417. * execution. It allows to handle missed signals, if any. In other case
  418. * work handler just validates that no new signals have been received
  419. * during masking.
  420. */
  421. cancel_delayed_work(&priv->dwork_irq);
  422. schedule_delayed_work(&priv->dwork_irq, 0);
  423. spin_unlock_irqrestore(&priv->lock, flags);
  424. return;
  425. unmask_event:
  426. priv->not_asserted++;
  427. /* Unmask aggregation event (no need acknowledge). */
  428. ret = regmap_write(priv->regmap, pdata->cell +
  429. MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
  430. out:
  431. if (ret)
  432. dev_err(priv->dev, "Failed to complete workqueue.\n");
  433. }
  434. static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv)
  435. {
  436. struct mlxreg_core_hotplug_platform_data *pdata;
  437. struct mlxreg_core_item *item;
  438. int i, ret;
  439. pdata = dev_get_platdata(&priv->pdev->dev);
  440. item = pdata->items;
  441. for (i = 0; i < pdata->counter; i++, item++) {
  442. /* Clear group presense event. */
  443. ret = regmap_write(priv->regmap, item->reg +
  444. MLXREG_HOTPLUG_EVENT_OFF, 0);
  445. if (ret)
  446. goto out;
  447. /* Set group initial status as mask and unmask group event. */
  448. if (item->inversed) {
  449. item->cache = item->mask;
  450. ret = regmap_write(priv->regmap, item->reg +
  451. MLXREG_HOTPLUG_MASK_OFF,
  452. item->mask);
  453. if (ret)
  454. goto out;
  455. }
  456. }
  457. /* Keep aggregation initial status as zero and unmask events. */
  458. ret = regmap_write(priv->regmap, pdata->cell +
  459. MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
  460. if (ret)
  461. goto out;
  462. /* Keep low aggregation initial status as zero and unmask events. */
  463. if (pdata->cell_low) {
  464. ret = regmap_write(priv->regmap, pdata->cell_low +
  465. MLXREG_HOTPLUG_AGGR_MASK_OFF,
  466. pdata->mask_low);
  467. if (ret)
  468. goto out;
  469. }
  470. /* Invoke work handler for initializing hot plug devices setting. */
  471. mlxreg_hotplug_work_handler(&priv->dwork_irq.work);
  472. out:
  473. if (ret)
  474. dev_err(priv->dev, "Failed to set interrupts.\n");
  475. enable_irq(priv->irq);
  476. return ret;
  477. }
  478. static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv)
  479. {
  480. struct mlxreg_core_hotplug_platform_data *pdata;
  481. struct mlxreg_core_item *item;
  482. struct mlxreg_core_data *data;
  483. int count, i, j;
  484. pdata = dev_get_platdata(&priv->pdev->dev);
  485. item = pdata->items;
  486. disable_irq(priv->irq);
  487. cancel_delayed_work_sync(&priv->dwork_irq);
  488. /* Mask low aggregation event, if defined. */
  489. if (pdata->cell_low)
  490. regmap_write(priv->regmap, pdata->cell_low +
  491. MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
  492. /* Mask aggregation event. */
  493. regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF,
  494. 0);
  495. /* Clear topology configurations. */
  496. for (i = 0; i < pdata->counter; i++, item++) {
  497. data = item->data;
  498. /* Mask group presense event. */
  499. regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF,
  500. 0);
  501. /* Clear group presense event. */
  502. regmap_write(priv->regmap, data->reg +
  503. MLXREG_HOTPLUG_EVENT_OFF, 0);
  504. /* Remove all the attached devices in group. */
  505. count = item->count;
  506. for (j = 0; j < count; j++, data++)
  507. mlxreg_hotplug_device_destroy(priv, data);
  508. }
  509. }
  510. static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev)
  511. {
  512. struct mlxreg_hotplug_priv_data *priv;
  513. priv = (struct mlxreg_hotplug_priv_data *)dev;
  514. /* Schedule work task for immediate execution.*/
  515. schedule_delayed_work(&priv->dwork_irq, 0);
  516. return IRQ_HANDLED;
  517. }
  518. static int mlxreg_hotplug_probe(struct platform_device *pdev)
  519. {
  520. struct mlxreg_core_hotplug_platform_data *pdata;
  521. struct mlxreg_hotplug_priv_data *priv;
  522. struct i2c_adapter *deferred_adap;
  523. int err;
  524. pdata = dev_get_platdata(&pdev->dev);
  525. if (!pdata) {
  526. dev_err(&pdev->dev, "Failed to get platform data.\n");
  527. return -EINVAL;
  528. }
  529. /* Defer probing if the necessary adapter is not configured yet. */
  530. deferred_adap = i2c_get_adapter(pdata->deferred_nr);
  531. if (!deferred_adap)
  532. return -EPROBE_DEFER;
  533. i2c_put_adapter(deferred_adap);
  534. priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
  535. if (!priv)
  536. return -ENOMEM;
  537. if (pdata->irq) {
  538. priv->irq = pdata->irq;
  539. } else {
  540. priv->irq = platform_get_irq(pdev, 0);
  541. if (priv->irq < 0) {
  542. dev_err(&pdev->dev, "Failed to get platform irq: %d\n",
  543. priv->irq);
  544. return priv->irq;
  545. }
  546. }
  547. priv->regmap = pdata->regmap;
  548. priv->dev = pdev->dev.parent;
  549. priv->pdev = pdev;
  550. err = devm_request_irq(&pdev->dev, priv->irq,
  551. mlxreg_hotplug_irq_handler, IRQF_TRIGGER_FALLING
  552. | IRQF_SHARED, "mlxreg-hotplug", priv);
  553. if (err) {
  554. dev_err(&pdev->dev, "Failed to request irq: %d\n", err);
  555. return err;
  556. }
  557. disable_irq(priv->irq);
  558. spin_lock_init(&priv->lock);
  559. INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler);
  560. dev_set_drvdata(&pdev->dev, priv);
  561. err = mlxreg_hotplug_attr_init(priv);
  562. if (err) {
  563. dev_err(&pdev->dev, "Failed to allocate attributes: %d\n",
  564. err);
  565. return err;
  566. }
  567. priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
  568. "mlxreg_hotplug", priv, priv->groups);
  569. if (IS_ERR(priv->hwmon)) {
  570. dev_err(&pdev->dev, "Failed to register hwmon device %ld\n",
  571. PTR_ERR(priv->hwmon));
  572. return PTR_ERR(priv->hwmon);
  573. }
  574. /* Perform initial interrupts setup. */
  575. mlxreg_hotplug_set_irq(priv);
  576. priv->after_probe = true;
  577. return 0;
  578. }
  579. static int mlxreg_hotplug_remove(struct platform_device *pdev)
  580. {
  581. struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev);
  582. /* Clean interrupts setup. */
  583. mlxreg_hotplug_unset_irq(priv);
  584. devm_free_irq(&pdev->dev, priv->irq, priv);
  585. return 0;
  586. }
  587. static struct platform_driver mlxreg_hotplug_driver = {
  588. .driver = {
  589. .name = "mlxreg-hotplug",
  590. },
  591. .probe = mlxreg_hotplug_probe,
  592. .remove = mlxreg_hotplug_remove,
  593. };
  594. module_platform_driver(mlxreg_hotplug_driver);
  595. MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
  596. MODULE_DESCRIPTION("Mellanox regmap hotplug platform driver");
  597. MODULE_LICENSE("Dual BSD/GPL");
  598. MODULE_ALIAS("platform:mlxreg-hotplug");