mlx-platform.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  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/module.h>
  38. #include <linux/platform_device.h>
  39. #include <linux/platform_data/i2c-mux-reg.h>
  40. #include <linux/platform_data/mlxcpld-hotplug.h>
  41. #define MLX_PLAT_DEVICE_NAME "mlxplat"
  42. /* LPC bus IO offsets */
  43. #define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000
  44. #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500
  45. #define MLXPLAT_CPLD_LPC_REG_AGGR_ADRR 0x253a
  46. #define MLXPLAT_CPLD_LPC_REG_PSU_ADRR 0x2558
  47. #define MLXPLAT_CPLD_LPC_REG_PWR_ADRR 0x2564
  48. #define MLXPLAT_CPLD_LPC_REG_FAN_ADRR 0x2588
  49. #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100
  50. #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb
  51. #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda
  52. #define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL
  53. #define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
  54. MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \
  55. MLXPLAT_CPLD_LPC_PIO_OFFSET)
  56. #define MLXPLAT_CPLD_LPC_REG2 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
  57. MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \
  58. MLXPLAT_CPLD_LPC_PIO_OFFSET)
  59. /* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */
  60. #define MLXPLAT_CPLD_AGGR_PSU_MASK_DEF 0x08
  61. #define MLXPLAT_CPLD_AGGR_PWR_MASK_DEF 0x08
  62. #define MLXPLAT_CPLD_AGGR_FAN_MASK_DEF 0x40
  63. #define MLXPLAT_CPLD_AGGR_MASK_DEF (MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \
  64. MLXPLAT_CPLD_AGGR_FAN_MASK_DEF)
  65. #define MLXPLAT_CPLD_AGGR_MASK_MSN21XX 0x04
  66. #define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0)
  67. #define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0)
  68. #define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0)
  69. /* Start channel numbers */
  70. #define MLXPLAT_CPLD_CH1 2
  71. #define MLXPLAT_CPLD_CH2 10
  72. /* Number of LPC attached MUX platform devices */
  73. #define MLXPLAT_CPLD_LPC_MUX_DEVS 2
  74. /* mlxplat_priv - platform private data
  75. * @pdev_i2c - i2c controller platform device
  76. * @pdev_mux - array of mux platform devices
  77. */
  78. struct mlxplat_priv {
  79. struct platform_device *pdev_i2c;
  80. struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
  81. struct platform_device *pdev_hotplug;
  82. };
  83. /* Regions for LPC I2C controller and LPC base register space */
  84. static const struct resource mlxplat_lpc_resources[] = {
  85. [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
  86. MLXPLAT_CPLD_LPC_IO_RANGE,
  87. "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO),
  88. [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR,
  89. MLXPLAT_CPLD_LPC_IO_RANGE,
  90. "mlxplat_cpld_lpc_regs",
  91. IORESOURCE_IO),
  92. };
  93. /* Platform default channels */
  94. static const int mlxplat_default_channels[][8] = {
  95. {
  96. MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
  97. MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
  98. 5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7
  99. },
  100. {
  101. MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2,
  102. MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 +
  103. 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7
  104. },
  105. };
  106. /* Platform channels for MSN21xx system family */
  107. static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
  108. /* Platform mux data */
  109. static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
  110. {
  111. .parent = 1,
  112. .base_nr = MLXPLAT_CPLD_CH1,
  113. .write_only = 1,
  114. .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
  115. .reg_size = 1,
  116. .idle_in_use = 1,
  117. },
  118. {
  119. .parent = 1,
  120. .base_nr = MLXPLAT_CPLD_CH2,
  121. .write_only = 1,
  122. .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
  123. .reg_size = 1,
  124. .idle_in_use = 1,
  125. },
  126. };
  127. /* Platform hotplug devices */
  128. static struct mlxcpld_hotplug_device mlxplat_mlxcpld_psu[] = {
  129. {
  130. .brdinfo = { I2C_BOARD_INFO("24c02", 0x51) },
  131. .bus = 10,
  132. },
  133. {
  134. .brdinfo = { I2C_BOARD_INFO("24c02", 0x50) },
  135. .bus = 10,
  136. },
  137. };
  138. static struct mlxcpld_hotplug_device mlxplat_mlxcpld_pwr[] = {
  139. {
  140. .brdinfo = { I2C_BOARD_INFO("dps460", 0x59) },
  141. .bus = 10,
  142. },
  143. {
  144. .brdinfo = { I2C_BOARD_INFO("dps460", 0x58) },
  145. .bus = 10,
  146. },
  147. };
  148. static struct mlxcpld_hotplug_device mlxplat_mlxcpld_fan[] = {
  149. {
  150. .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
  151. .bus = 11,
  152. },
  153. {
  154. .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
  155. .bus = 12,
  156. },
  157. {
  158. .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
  159. .bus = 13,
  160. },
  161. {
  162. .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
  163. .bus = 14,
  164. },
  165. };
  166. /* Platform hotplug default data */
  167. static
  168. struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_default_data = {
  169. .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR,
  170. .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
  171. .top_aggr_psu_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
  172. .psu_reg_offset = MLXPLAT_CPLD_LPC_REG_PSU_ADRR,
  173. .psu_mask = MLXPLAT_CPLD_PSU_MASK,
  174. .psu_count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
  175. .psu = mlxplat_mlxcpld_psu,
  176. .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
  177. .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR,
  178. .pwr_mask = MLXPLAT_CPLD_PWR_MASK,
  179. .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
  180. .pwr = mlxplat_mlxcpld_pwr,
  181. .top_aggr_fan_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
  182. .fan_reg_offset = MLXPLAT_CPLD_LPC_REG_FAN_ADRR,
  183. .fan_mask = MLXPLAT_CPLD_FAN_MASK,
  184. .fan_count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
  185. .fan = mlxplat_mlxcpld_fan,
  186. };
  187. /* Platform hotplug MSN21xx system family data */
  188. static
  189. struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
  190. .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR,
  191. .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX,
  192. .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX,
  193. .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR,
  194. .pwr_mask = MLXPLAT_CPLD_PWR_MASK,
  195. .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
  196. };
  197. static struct resource mlxplat_mlxcpld_resources[] = {
  198. [0] = DEFINE_RES_IRQ_NAMED(17, "mlxcpld-hotplug"),
  199. };
  200. struct platform_device *mlxplat_dev;
  201. struct mlxcpld_hotplug_platform_data *mlxplat_hotplug;
  202. static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
  203. {
  204. int i;
  205. for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
  206. mlxplat_mux_data[i].values = mlxplat_default_channels[i];
  207. mlxplat_mux_data[i].n_values =
  208. ARRAY_SIZE(mlxplat_default_channels[i]);
  209. }
  210. mlxplat_hotplug = &mlxplat_mlxcpld_default_data;
  211. return 1;
  212. };
  213. static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
  214. {
  215. int i;
  216. for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
  217. mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
  218. mlxplat_mux_data[i].n_values =
  219. ARRAY_SIZE(mlxplat_msn21xx_channels);
  220. }
  221. mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data;
  222. return 1;
  223. };
  224. static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
  225. {
  226. .callback = mlxplat_dmi_default_matched,
  227. .matches = {
  228. DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
  229. DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
  230. },
  231. },
  232. {
  233. .callback = mlxplat_dmi_default_matched,
  234. .matches = {
  235. DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
  236. DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
  237. },
  238. },
  239. {
  240. .callback = mlxplat_dmi_default_matched,
  241. .matches = {
  242. DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
  243. DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
  244. },
  245. },
  246. {
  247. .callback = mlxplat_dmi_default_matched,
  248. .matches = {
  249. DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
  250. DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
  251. },
  252. },
  253. {
  254. .callback = mlxplat_dmi_msn21xx_matched,
  255. .matches = {
  256. DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
  257. DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
  258. },
  259. },
  260. { }
  261. };
  262. static int __init mlxplat_init(void)
  263. {
  264. struct mlxplat_priv *priv;
  265. int i, err;
  266. if (!dmi_check_system(mlxplat_dmi_table))
  267. return -ENODEV;
  268. mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
  269. mlxplat_lpc_resources,
  270. ARRAY_SIZE(mlxplat_lpc_resources));
  271. if (IS_ERR(mlxplat_dev))
  272. return PTR_ERR(mlxplat_dev);
  273. priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
  274. GFP_KERNEL);
  275. if (!priv) {
  276. err = -ENOMEM;
  277. goto fail_alloc;
  278. }
  279. platform_set_drvdata(mlxplat_dev, priv);
  280. priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1,
  281. NULL, 0);
  282. if (IS_ERR(priv->pdev_i2c)) {
  283. err = PTR_ERR(priv->pdev_i2c);
  284. goto fail_alloc;
  285. }
  286. for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
  287. priv->pdev_mux[i] = platform_device_register_resndata(
  288. &mlxplat_dev->dev,
  289. "i2c-mux-reg", i, NULL,
  290. 0, &mlxplat_mux_data[i],
  291. sizeof(mlxplat_mux_data[i]));
  292. if (IS_ERR(priv->pdev_mux[i])) {
  293. err = PTR_ERR(priv->pdev_mux[i]);
  294. goto fail_platform_mux_register;
  295. }
  296. }
  297. priv->pdev_hotplug = platform_device_register_resndata(
  298. &mlxplat_dev->dev, "mlxcpld-hotplug",
  299. PLATFORM_DEVID_NONE,
  300. mlxplat_mlxcpld_resources,
  301. ARRAY_SIZE(mlxplat_mlxcpld_resources),
  302. mlxplat_hotplug, sizeof(*mlxplat_hotplug));
  303. if (IS_ERR(priv->pdev_hotplug)) {
  304. err = PTR_ERR(priv->pdev_hotplug);
  305. goto fail_platform_mux_register;
  306. }
  307. return 0;
  308. fail_platform_mux_register:
  309. while (--i >= 0)
  310. platform_device_unregister(priv->pdev_mux[i]);
  311. platform_device_unregister(priv->pdev_i2c);
  312. fail_alloc:
  313. platform_device_unregister(mlxplat_dev);
  314. return err;
  315. }
  316. module_init(mlxplat_init);
  317. static void __exit mlxplat_exit(void)
  318. {
  319. struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
  320. int i;
  321. platform_device_unregister(priv->pdev_hotplug);
  322. for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
  323. platform_device_unregister(priv->pdev_mux[i]);
  324. platform_device_unregister(priv->pdev_i2c);
  325. platform_device_unregister(mlxplat_dev);
  326. }
  327. module_exit(mlxplat_exit);
  328. MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
  329. MODULE_DESCRIPTION("Mellanox platform driver");
  330. MODULE_LICENSE("Dual BSD/GPL");
  331. MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:");
  332. MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:");
  333. MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:");
  334. MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:");
  335. MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:");