mlx-platform.c 11 KB

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