mlx-platform.c 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001
  1. /*
  2. * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
  3. * Copyright (c) 2016 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/device.h>
  34. #include <linux/dmi.h>
  35. #include <linux/i2c.h>
  36. #include <linux/i2c-mux.h>
  37. #include <linux/io.h>
  38. #include <linux/module.h>
  39. #include <linux/platform_device.h>
  40. #include <linux/platform_data/i2c-mux-reg.h>
  41. #include <linux/platform_data/mlxreg.h>
  42. #include <linux/regmap.h>
  43. #define MLX_PLAT_DEVICE_NAME "mlxplat"
  44. /* LPC bus IO offsets */
  45. #define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000
  46. #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500
  47. #define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a
  48. #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b
  49. #define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40
  50. #define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41
  51. #define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58
  52. #define MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET 0x59
  53. #define MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET 0x5a
  54. #define MLXPLAT_CPLD_LPC_REG_PWR_OFFSET 0x64
  55. #define MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET 0x65
  56. #define MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET 0x66
  57. #define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88
  58. #define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89
  59. #define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a
  60. #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100
  61. #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb
  62. #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda
  63. #define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL
  64. #define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
  65. MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \
  66. MLXPLAT_CPLD_LPC_PIO_OFFSET)
  67. #define MLXPLAT_CPLD_LPC_REG2 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
  68. MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \
  69. MLXPLAT_CPLD_LPC_PIO_OFFSET)
  70. /* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */
  71. #define MLXPLAT_CPLD_AGGR_PSU_MASK_DEF 0x08
  72. #define MLXPLAT_CPLD_AGGR_PWR_MASK_DEF 0x08
  73. #define MLXPLAT_CPLD_AGGR_FAN_MASK_DEF 0x40
  74. #define MLXPLAT_CPLD_AGGR_MASK_DEF (MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \
  75. MLXPLAT_CPLD_AGGR_FAN_MASK_DEF)
  76. #define MLXPLAT_CPLD_AGGR_MASK_NG_DEF 0x04
  77. #define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc0
  78. #define MLXPLAT_CPLD_AGGR_MASK_MSN21XX 0x04
  79. #define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0)
  80. #define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0)
  81. #define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0)
  82. #define MLXPLAT_CPLD_FAN_NG_MASK GENMASK(5, 0)
  83. /* Default I2C parent bus number */
  84. #define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1
  85. /* Maximum number of possible physical buses equipped on system */
  86. #define MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM 16
  87. /* Number of channels in group */
  88. #define MLXPLAT_CPLD_GRP_CHNL_NUM 8
  89. /* Start channel numbers */
  90. #define MLXPLAT_CPLD_CH1 2
  91. #define MLXPLAT_CPLD_CH2 10
  92. /* Number of LPC attached MUX platform devices */
  93. #define MLXPLAT_CPLD_LPC_MUX_DEVS 2
  94. /* Hotplug devices adapter numbers */
  95. #define MLXPLAT_CPLD_NR_NONE -1
  96. #define MLXPLAT_CPLD_PSU_DEFAULT_NR 10
  97. #define MLXPLAT_CPLD_PSU_MSNXXXX_NR 4
  98. #define MLXPLAT_CPLD_FAN1_DEFAULT_NR 11
  99. #define MLXPLAT_CPLD_FAN2_DEFAULT_NR 12
  100. #define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13
  101. #define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14
  102. /* mlxplat_priv - platform private data
  103. * @pdev_i2c - i2c controller platform device
  104. * @pdev_mux - array of mux platform devices
  105. * @pdev_hotplug - hotplug platform devices
  106. */
  107. struct mlxplat_priv {
  108. struct platform_device *pdev_i2c;
  109. struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
  110. struct platform_device *pdev_hotplug;
  111. };
  112. /* Regions for LPC I2C controller and LPC base register space */
  113. static const struct resource mlxplat_lpc_resources[] = {
  114. [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
  115. MLXPLAT_CPLD_LPC_IO_RANGE,
  116. "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO),
  117. [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR,
  118. MLXPLAT_CPLD_LPC_IO_RANGE,
  119. "mlxplat_cpld_lpc_regs",
  120. IORESOURCE_IO),
  121. };
  122. /* Platform default channels */
  123. static const int mlxplat_default_channels[][MLXPLAT_CPLD_GRP_CHNL_NUM] = {
  124. {
  125. MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
  126. MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
  127. 5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7
  128. },
  129. {
  130. MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2,
  131. MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 +
  132. 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7
  133. },
  134. };
  135. /* Platform channels for MSN21xx system family */
  136. static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
  137. /* Platform mux data */
  138. static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
  139. {
  140. .parent = 1,
  141. .base_nr = MLXPLAT_CPLD_CH1,
  142. .write_only = 1,
  143. .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
  144. .reg_size = 1,
  145. .idle_in_use = 1,
  146. },
  147. {
  148. .parent = 1,
  149. .base_nr = MLXPLAT_CPLD_CH2,
  150. .write_only = 1,
  151. .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
  152. .reg_size = 1,
  153. .idle_in_use = 1,
  154. },
  155. };
  156. /* Platform hotplug devices */
  157. static struct i2c_board_info mlxplat_mlxcpld_psu[] = {
  158. {
  159. I2C_BOARD_INFO("24c02", 0x51),
  160. },
  161. {
  162. I2C_BOARD_INFO("24c02", 0x50),
  163. },
  164. };
  165. static struct i2c_board_info mlxplat_mlxcpld_ng_psu[] = {
  166. {
  167. I2C_BOARD_INFO("24c32", 0x51),
  168. },
  169. {
  170. I2C_BOARD_INFO("24c32", 0x50),
  171. },
  172. };
  173. static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
  174. {
  175. I2C_BOARD_INFO("dps460", 0x59),
  176. },
  177. {
  178. I2C_BOARD_INFO("dps460", 0x58),
  179. },
  180. };
  181. static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
  182. {
  183. I2C_BOARD_INFO("24c32", 0x50),
  184. },
  185. {
  186. I2C_BOARD_INFO("24c32", 0x50),
  187. },
  188. {
  189. I2C_BOARD_INFO("24c32", 0x50),
  190. },
  191. {
  192. I2C_BOARD_INFO("24c32", 0x50),
  193. },
  194. };
  195. /* Platform hotplug default data */
  196. static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = {
  197. {
  198. .label = "psu1",
  199. .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
  200. .mask = BIT(0),
  201. .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
  202. .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
  203. },
  204. {
  205. .label = "psu2",
  206. .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
  207. .mask = BIT(1),
  208. .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
  209. .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
  210. },
  211. };
  212. static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = {
  213. {
  214. .label = "pwr1",
  215. .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
  216. .mask = BIT(0),
  217. .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
  218. .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
  219. },
  220. {
  221. .label = "pwr2",
  222. .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
  223. .mask = BIT(1),
  224. .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
  225. .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
  226. },
  227. };
  228. static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = {
  229. {
  230. .label = "fan1",
  231. .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
  232. .mask = BIT(0),
  233. .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0],
  234. .hpdev.nr = MLXPLAT_CPLD_FAN1_DEFAULT_NR,
  235. },
  236. {
  237. .label = "fan2",
  238. .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
  239. .mask = BIT(1),
  240. .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1],
  241. .hpdev.nr = MLXPLAT_CPLD_FAN2_DEFAULT_NR,
  242. },
  243. {
  244. .label = "fan3",
  245. .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
  246. .mask = BIT(2),
  247. .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2],
  248. .hpdev.nr = MLXPLAT_CPLD_FAN3_DEFAULT_NR,
  249. },
  250. {
  251. .label = "fan4",
  252. .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
  253. .mask = BIT(3),
  254. .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3],
  255. .hpdev.nr = MLXPLAT_CPLD_FAN4_DEFAULT_NR,
  256. },
  257. };
  258. static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = {
  259. {
  260. .data = mlxplat_mlxcpld_default_psu_items_data,
  261. .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
  262. .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
  263. .mask = MLXPLAT_CPLD_PSU_MASK,
  264. .count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
  265. .inversed = 1,
  266. .health = false,
  267. },
  268. {
  269. .data = mlxplat_mlxcpld_default_pwr_items_data,
  270. .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
  271. .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
  272. .mask = MLXPLAT_CPLD_PWR_MASK,
  273. .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
  274. .inversed = 0,
  275. .health = false,
  276. },
  277. {
  278. .data = mlxplat_mlxcpld_default_fan_items_data,
  279. .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
  280. .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
  281. .mask = MLXPLAT_CPLD_FAN_MASK,
  282. .count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
  283. .inversed = 1,
  284. .health = false,
  285. },
  286. };
  287. static
  288. struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = {
  289. .items = mlxplat_mlxcpld_default_items,
  290. .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items),
  291. .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
  292. .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
  293. };
  294. static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data[] = {
  295. {
  296. .label = "pwr1",
  297. .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
  298. .mask = BIT(0),
  299. .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
  300. },
  301. {
  302. .label = "pwr2",
  303. .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
  304. .mask = BIT(1),
  305. .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
  306. },
  307. };
  308. /* Platform hotplug MSN21xx system family data */
  309. static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = {
  310. {
  311. .data = mlxplat_mlxcpld_msn21xx_pwr_items_data,
  312. .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
  313. .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
  314. .mask = MLXPLAT_CPLD_PWR_MASK,
  315. .count = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_pwr_items_data),
  316. .inversed = 0,
  317. .health = false,
  318. },
  319. };
  320. static
  321. struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
  322. .items = mlxplat_mlxcpld_msn21xx_items,
  323. .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items),
  324. .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
  325. .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
  326. .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
  327. .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
  328. };
  329. /* Platform hotplug msn274x system family data */
  330. static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_psu_items_data[] = {
  331. {
  332. .label = "psu1",
  333. .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
  334. .mask = BIT(0),
  335. .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
  336. .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
  337. },
  338. {
  339. .label = "psu2",
  340. .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
  341. .mask = BIT(1),
  342. .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
  343. .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
  344. },
  345. };
  346. static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_pwr_items_data[] = {
  347. {
  348. .label = "pwr1",
  349. .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
  350. .mask = BIT(0),
  351. .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
  352. .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
  353. },
  354. {
  355. .label = "pwr2",
  356. .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
  357. .mask = BIT(1),
  358. .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
  359. .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
  360. },
  361. };
  362. static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_fan_items_data[] = {
  363. {
  364. .label = "fan1",
  365. .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
  366. .mask = BIT(0),
  367. .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
  368. },
  369. {
  370. .label = "fan2",
  371. .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
  372. .mask = BIT(1),
  373. .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
  374. },
  375. {
  376. .label = "fan3",
  377. .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
  378. .mask = BIT(2),
  379. .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
  380. },
  381. {
  382. .label = "fan4",
  383. .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
  384. .mask = BIT(3),
  385. .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
  386. },
  387. };
  388. static struct mlxreg_core_item mlxplat_mlxcpld_msn274x_items[] = {
  389. {
  390. .data = mlxplat_mlxcpld_msn274x_psu_items_data,
  391. .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
  392. .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
  393. .mask = MLXPLAT_CPLD_PSU_MASK,
  394. .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_psu_items_data),
  395. .inversed = 1,
  396. .health = false,
  397. },
  398. {
  399. .data = mlxplat_mlxcpld_default_ng_pwr_items_data,
  400. .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
  401. .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
  402. .mask = MLXPLAT_CPLD_PWR_MASK,
  403. .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data),
  404. .inversed = 0,
  405. .health = false,
  406. },
  407. {
  408. .data = mlxplat_mlxcpld_msn274x_fan_items_data,
  409. .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
  410. .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
  411. .mask = MLXPLAT_CPLD_FAN_MASK,
  412. .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_fan_items_data),
  413. .inversed = 1,
  414. .health = false,
  415. },
  416. };
  417. static
  418. struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn274x_data = {
  419. .items = mlxplat_mlxcpld_msn274x_items,
  420. .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_items),
  421. .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
  422. .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
  423. .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
  424. .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
  425. };
  426. /* Platform hotplug MSN201x system family data */
  427. static struct mlxreg_core_data mlxplat_mlxcpld_msn201x_pwr_items_data[] = {
  428. {
  429. .label = "pwr1",
  430. .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
  431. .mask = BIT(0),
  432. .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
  433. },
  434. {
  435. .label = "pwr2",
  436. .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
  437. .mask = BIT(1),
  438. .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
  439. },
  440. };
  441. static struct mlxreg_core_item mlxplat_mlxcpld_msn201x_items[] = {
  442. {
  443. .data = mlxplat_mlxcpld_msn201x_pwr_items_data,
  444. .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
  445. .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
  446. .mask = MLXPLAT_CPLD_PWR_MASK,
  447. .count = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_pwr_items_data),
  448. .inversed = 0,
  449. .health = false,
  450. },
  451. };
  452. static
  453. struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn201x_data = {
  454. .items = mlxplat_mlxcpld_msn21xx_items,
  455. .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_items),
  456. .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
  457. .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
  458. .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
  459. .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
  460. };
  461. /* Platform hotplug next generation system family data */
  462. static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_psu_items_data[] = {
  463. {
  464. .label = "psu1",
  465. .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
  466. .mask = BIT(0),
  467. .hpdev.brdinfo = &mlxplat_mlxcpld_ng_psu[0],
  468. .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
  469. },
  470. {
  471. .label = "psu2",
  472. .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
  473. .mask = BIT(1),
  474. .hpdev.brdinfo = &mlxplat_mlxcpld_ng_psu[1],
  475. .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
  476. },
  477. };
  478. static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_fan_items_data[] = {
  479. {
  480. .label = "fan1",
  481. .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
  482. .mask = BIT(0),
  483. .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
  484. },
  485. {
  486. .label = "fan2",
  487. .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
  488. .mask = BIT(1),
  489. .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
  490. },
  491. {
  492. .label = "fan3",
  493. .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
  494. .mask = BIT(2),
  495. .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
  496. },
  497. {
  498. .label = "fan4",
  499. .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
  500. .mask = BIT(3),
  501. .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
  502. },
  503. {
  504. .label = "fan5",
  505. .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
  506. .mask = BIT(4),
  507. .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
  508. },
  509. {
  510. .label = "fan6",
  511. .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
  512. .mask = BIT(5),
  513. .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
  514. },
  515. };
  516. static struct mlxreg_core_item mlxplat_mlxcpld_default_ng_items[] = {
  517. {
  518. .data = mlxplat_mlxcpld_default_ng_psu_items_data,
  519. .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
  520. .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
  521. .mask = MLXPLAT_CPLD_PSU_MASK,
  522. .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_psu_items_data),
  523. .inversed = 1,
  524. .health = false,
  525. },
  526. {
  527. .data = mlxplat_mlxcpld_default_ng_pwr_items_data,
  528. .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
  529. .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
  530. .mask = MLXPLAT_CPLD_PWR_MASK,
  531. .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data),
  532. .inversed = 0,
  533. .health = false,
  534. },
  535. {
  536. .data = mlxplat_mlxcpld_default_ng_fan_items_data,
  537. .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
  538. .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
  539. .mask = MLXPLAT_CPLD_FAN_NG_MASK,
  540. .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data),
  541. .inversed = 1,
  542. .health = false,
  543. },
  544. };
  545. static
  546. struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = {
  547. .items = mlxplat_mlxcpld_default_ng_items,
  548. .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_items),
  549. .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
  550. .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
  551. .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
  552. .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
  553. };
  554. static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
  555. {
  556. switch (reg) {
  557. case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
  558. case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
  559. case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
  560. case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
  561. case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
  562. case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
  563. case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
  564. case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
  565. return true;
  566. }
  567. return false;
  568. }
  569. static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
  570. {
  571. switch (reg) {
  572. case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
  573. case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
  574. case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
  575. case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
  576. case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
  577. case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
  578. case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
  579. case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
  580. case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
  581. case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
  582. case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
  583. case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
  584. case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
  585. return true;
  586. }
  587. return false;
  588. }
  589. static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
  590. {
  591. switch (reg) {
  592. case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
  593. case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
  594. case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
  595. case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
  596. case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
  597. case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
  598. case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
  599. case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
  600. case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
  601. case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
  602. case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
  603. case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
  604. case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
  605. return true;
  606. }
  607. return false;
  608. }
  609. struct mlxplat_mlxcpld_regmap_context {
  610. void __iomem *base;
  611. };
  612. static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx;
  613. static int
  614. mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val)
  615. {
  616. struct mlxplat_mlxcpld_regmap_context *ctx = context;
  617. *val = ioread8(ctx->base + reg);
  618. return 0;
  619. }
  620. static int
  621. mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val)
  622. {
  623. struct mlxplat_mlxcpld_regmap_context *ctx = context;
  624. iowrite8(val, ctx->base + reg);
  625. return 0;
  626. }
  627. static const struct regmap_config mlxplat_mlxcpld_regmap_config = {
  628. .reg_bits = 8,
  629. .val_bits = 8,
  630. .max_register = 255,
  631. .cache_type = REGCACHE_FLAT,
  632. .writeable_reg = mlxplat_mlxcpld_writeable_reg,
  633. .readable_reg = mlxplat_mlxcpld_readable_reg,
  634. .volatile_reg = mlxplat_mlxcpld_volatile_reg,
  635. .reg_read = mlxplat_mlxcpld_reg_read,
  636. .reg_write = mlxplat_mlxcpld_reg_write,
  637. };
  638. static struct resource mlxplat_mlxcpld_resources[] = {
  639. [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
  640. };
  641. static struct platform_device *mlxplat_dev;
  642. static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
  643. static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
  644. {
  645. int i;
  646. for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
  647. mlxplat_mux_data[i].values = mlxplat_default_channels[i];
  648. mlxplat_mux_data[i].n_values =
  649. ARRAY_SIZE(mlxplat_default_channels[i]);
  650. }
  651. mlxplat_hotplug = &mlxplat_mlxcpld_default_data;
  652. mlxplat_hotplug->deferred_nr =
  653. mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
  654. return 1;
  655. };
  656. static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
  657. {
  658. int i;
  659. for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
  660. mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
  661. mlxplat_mux_data[i].n_values =
  662. ARRAY_SIZE(mlxplat_msn21xx_channels);
  663. }
  664. mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data;
  665. mlxplat_hotplug->deferred_nr =
  666. mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
  667. return 1;
  668. };
  669. static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi)
  670. {
  671. int i;
  672. for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
  673. mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
  674. mlxplat_mux_data[i].n_values =
  675. ARRAY_SIZE(mlxplat_msn21xx_channels);
  676. }
  677. mlxplat_hotplug = &mlxplat_mlxcpld_msn274x_data;
  678. mlxplat_hotplug->deferred_nr =
  679. mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
  680. return 1;
  681. };
  682. static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi)
  683. {
  684. int i;
  685. for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
  686. mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
  687. mlxplat_mux_data[i].n_values =
  688. ARRAY_SIZE(mlxplat_msn21xx_channels);
  689. }
  690. mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data;
  691. mlxplat_hotplug->deferred_nr =
  692. mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
  693. return 1;
  694. };
  695. static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi)
  696. {
  697. int i;
  698. for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
  699. mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
  700. mlxplat_mux_data[i].n_values =
  701. ARRAY_SIZE(mlxplat_msn21xx_channels);
  702. }
  703. mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data;
  704. mlxplat_hotplug->deferred_nr =
  705. mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
  706. return 1;
  707. };
  708. static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
  709. {
  710. .callback = mlxplat_dmi_msn274x_matched,
  711. .matches = {
  712. DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
  713. DMI_MATCH(DMI_PRODUCT_NAME, "MSN274"),
  714. },
  715. },
  716. {
  717. .callback = mlxplat_dmi_default_matched,
  718. .matches = {
  719. DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
  720. DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
  721. },
  722. },
  723. {
  724. .callback = mlxplat_dmi_default_matched,
  725. .matches = {
  726. DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
  727. DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
  728. },
  729. },
  730. {
  731. .callback = mlxplat_dmi_default_matched,
  732. .matches = {
  733. DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
  734. DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
  735. },
  736. },
  737. {
  738. .callback = mlxplat_dmi_default_matched,
  739. .matches = {
  740. DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
  741. DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
  742. },
  743. },
  744. {
  745. .callback = mlxplat_dmi_msn21xx_matched,
  746. .matches = {
  747. DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
  748. DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
  749. },
  750. },
  751. {
  752. .callback = mlxplat_dmi_msn201x_matched,
  753. .matches = {
  754. DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
  755. DMI_MATCH(DMI_PRODUCT_NAME, "MSN201"),
  756. },
  757. },
  758. {
  759. .callback = mlxplat_dmi_qmb7xx_matched,
  760. .matches = {
  761. DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
  762. DMI_MATCH(DMI_PRODUCT_NAME, "QMB7"),
  763. },
  764. },
  765. {
  766. .callback = mlxplat_dmi_qmb7xx_matched,
  767. .matches = {
  768. DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
  769. DMI_MATCH(DMI_PRODUCT_NAME, "SN37"),
  770. },
  771. },
  772. {
  773. .callback = mlxplat_dmi_qmb7xx_matched,
  774. .matches = {
  775. DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
  776. DMI_MATCH(DMI_PRODUCT_NAME, "SN34"),
  777. },
  778. },
  779. { }
  780. };
  781. MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table);
  782. static int mlxplat_mlxcpld_verify_bus_topology(int *nr)
  783. {
  784. struct i2c_adapter *search_adap;
  785. int shift, i;
  786. /* Scan adapters from expected id to verify it is free. */
  787. *nr = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR;
  788. for (i = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; i <
  789. MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; i++) {
  790. search_adap = i2c_get_adapter(i);
  791. if (search_adap) {
  792. i2c_put_adapter(search_adap);
  793. continue;
  794. }
  795. /* Return if expected parent adapter is free. */
  796. if (i == MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR)
  797. return 0;
  798. break;
  799. }
  800. /* Return with error if free id for adapter is not found. */
  801. if (i == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM)
  802. return -ENODEV;
  803. /* Shift adapter ids, since expected parent adapter is not free. */
  804. *nr = i;
  805. for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
  806. shift = *nr - mlxplat_mux_data[i].parent;
  807. mlxplat_mux_data[i].parent = *nr;
  808. mlxplat_mux_data[i].base_nr += shift;
  809. if (shift > 0)
  810. mlxplat_hotplug->shift_nr = shift;
  811. }
  812. return 0;
  813. }
  814. static int __init mlxplat_init(void)
  815. {
  816. struct mlxplat_priv *priv;
  817. int i, nr, err;
  818. if (!dmi_check_system(mlxplat_dmi_table))
  819. return -ENODEV;
  820. mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
  821. mlxplat_lpc_resources,
  822. ARRAY_SIZE(mlxplat_lpc_resources));
  823. if (IS_ERR(mlxplat_dev))
  824. return PTR_ERR(mlxplat_dev);
  825. priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
  826. GFP_KERNEL);
  827. if (!priv) {
  828. err = -ENOMEM;
  829. goto fail_alloc;
  830. }
  831. platform_set_drvdata(mlxplat_dev, priv);
  832. err = mlxplat_mlxcpld_verify_bus_topology(&nr);
  833. if (nr < 0)
  834. goto fail_alloc;
  835. nr = (nr == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) ? -1 : nr;
  836. priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", nr,
  837. NULL, 0);
  838. if (IS_ERR(priv->pdev_i2c)) {
  839. err = PTR_ERR(priv->pdev_i2c);
  840. goto fail_alloc;
  841. }
  842. for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
  843. priv->pdev_mux[i] = platform_device_register_resndata(
  844. &mlxplat_dev->dev,
  845. "i2c-mux-reg", i, NULL,
  846. 0, &mlxplat_mux_data[i],
  847. sizeof(mlxplat_mux_data[i]));
  848. if (IS_ERR(priv->pdev_mux[i])) {
  849. err = PTR_ERR(priv->pdev_mux[i]);
  850. goto fail_platform_mux_register;
  851. }
  852. }
  853. mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev,
  854. mlxplat_lpc_resources[1].start, 1);
  855. if (!mlxplat_mlxcpld_regmap_ctx.base) {
  856. err = -ENOMEM;
  857. goto fail_platform_mux_register;
  858. }
  859. mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
  860. &mlxplat_mlxcpld_regmap_ctx,
  861. &mlxplat_mlxcpld_regmap_config);
  862. if (IS_ERR(mlxplat_hotplug->regmap)) {
  863. err = PTR_ERR(mlxplat_hotplug->regmap);
  864. goto fail_platform_mux_register;
  865. }
  866. priv->pdev_hotplug = platform_device_register_resndata(
  867. &mlxplat_dev->dev, "mlxreg-hotplug",
  868. PLATFORM_DEVID_NONE,
  869. mlxplat_mlxcpld_resources,
  870. ARRAY_SIZE(mlxplat_mlxcpld_resources),
  871. mlxplat_hotplug, sizeof(*mlxplat_hotplug));
  872. if (IS_ERR(priv->pdev_hotplug)) {
  873. err = PTR_ERR(priv->pdev_hotplug);
  874. goto fail_platform_mux_register;
  875. }
  876. /* Sync registers with hardware. */
  877. regcache_mark_dirty(mlxplat_hotplug->regmap);
  878. err = regcache_sync(mlxplat_hotplug->regmap);
  879. if (err)
  880. goto fail_platform_hotplug_register;
  881. return 0;
  882. fail_platform_hotplug_register:
  883. platform_device_unregister(priv->pdev_hotplug);
  884. fail_platform_mux_register:
  885. while (--i >= 0)
  886. platform_device_unregister(priv->pdev_mux[i]);
  887. platform_device_unregister(priv->pdev_i2c);
  888. fail_alloc:
  889. platform_device_unregister(mlxplat_dev);
  890. return err;
  891. }
  892. module_init(mlxplat_init);
  893. static void __exit mlxplat_exit(void)
  894. {
  895. struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
  896. int i;
  897. platform_device_unregister(priv->pdev_hotplug);
  898. for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
  899. platform_device_unregister(priv->pdev_mux[i]);
  900. platform_device_unregister(priv->pdev_i2c);
  901. platform_device_unregister(mlxplat_dev);
  902. }
  903. module_exit(mlxplat_exit);
  904. MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
  905. MODULE_DESCRIPTION("Mellanox platform driver");
  906. MODULE_LICENSE("Dual BSD/GPL");