mlx-platform.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /*
  2. * arch/x86/platform/mellanox/mlx-platform.c
  3. * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
  4. * Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com>
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the names of the copyright holders nor the names of its
  15. * contributors may be used to endorse or promote products derived from
  16. * this software without specific prior written permission.
  17. *
  18. * Alternatively, this software may be distributed under the terms of the
  19. * GNU General Public License ("GPL") version 2 as published by the Free
  20. * Software Foundation.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  23. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  26. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  29. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  30. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  31. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. #include <linux/device.h>
  35. #include <linux/dmi.h>
  36. #include <linux/i2c.h>
  37. #include <linux/i2c-mux.h>
  38. #include <linux/module.h>
  39. #include <linux/platform_device.h>
  40. #include <linux/platform_data/i2c-mux-reg.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. };
  68. /* Regions for LPC I2C controller and LPC base register space */
  69. static const struct resource mlxplat_lpc_resources[] = {
  70. [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
  71. MLXPLAT_CPLD_LPC_IO_RANGE,
  72. "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO),
  73. [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR,
  74. MLXPLAT_CPLD_LPC_IO_RANGE,
  75. "mlxplat_cpld_lpc_regs",
  76. IORESOURCE_IO),
  77. };
  78. /* Platform default channels */
  79. static const int mlxplat_default_channels[][8] = {
  80. {
  81. MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
  82. MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
  83. 5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7
  84. },
  85. {
  86. MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2,
  87. MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 +
  88. 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7
  89. },
  90. };
  91. /* Platform channels for MSN21xx system family */
  92. static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
  93. /* Platform mux data */
  94. static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
  95. {
  96. .parent = 1,
  97. .base_nr = MLXPLAT_CPLD_CH1,
  98. .write_only = 1,
  99. .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
  100. .reg_size = 1,
  101. .idle_in_use = 1,
  102. },
  103. {
  104. .parent = 1,
  105. .base_nr = MLXPLAT_CPLD_CH2,
  106. .write_only = 1,
  107. .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
  108. .reg_size = 1,
  109. .idle_in_use = 1,
  110. },
  111. };
  112. static struct platform_device *mlxplat_dev;
  113. static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
  114. {
  115. int i;
  116. for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
  117. mlxplat_mux_data[i].values = mlxplat_default_channels[i];
  118. mlxplat_mux_data[i].n_values =
  119. ARRAY_SIZE(mlxplat_default_channels[i]);
  120. }
  121. return 1;
  122. };
  123. static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
  124. {
  125. int i;
  126. for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
  127. mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
  128. mlxplat_mux_data[i].n_values =
  129. ARRAY_SIZE(mlxplat_msn21xx_channels);
  130. }
  131. return 1;
  132. };
  133. static struct dmi_system_id mlxplat_dmi_table[] __initdata = {
  134. {
  135. .callback = mlxplat_dmi_default_matched,
  136. .matches = {
  137. DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
  138. DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
  139. },
  140. },
  141. {
  142. .callback = mlxplat_dmi_default_matched,
  143. .matches = {
  144. DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
  145. DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
  146. },
  147. },
  148. {
  149. .callback = mlxplat_dmi_default_matched,
  150. .matches = {
  151. DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
  152. DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
  153. },
  154. },
  155. {
  156. .callback = mlxplat_dmi_default_matched,
  157. .matches = {
  158. DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
  159. DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
  160. },
  161. },
  162. {
  163. .callback = mlxplat_dmi_msn21xx_matched,
  164. .matches = {
  165. DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
  166. DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
  167. },
  168. },
  169. { }
  170. };
  171. static int __init mlxplat_init(void)
  172. {
  173. struct mlxplat_priv *priv;
  174. int i, err;
  175. if (!dmi_check_system(mlxplat_dmi_table))
  176. return -ENODEV;
  177. mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
  178. mlxplat_lpc_resources,
  179. ARRAY_SIZE(mlxplat_lpc_resources));
  180. if (IS_ERR(mlxplat_dev))
  181. return PTR_ERR(mlxplat_dev);
  182. priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
  183. GFP_KERNEL);
  184. if (!priv) {
  185. err = -ENOMEM;
  186. goto fail_alloc;
  187. }
  188. platform_set_drvdata(mlxplat_dev, priv);
  189. priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1,
  190. NULL, 0);
  191. if (IS_ERR(priv->pdev_i2c)) {
  192. err = PTR_ERR(priv->pdev_i2c);
  193. goto fail_alloc;
  194. };
  195. for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
  196. priv->pdev_mux[i] = platform_device_register_resndata(
  197. &mlxplat_dev->dev,
  198. "i2c-mux-reg", i, NULL,
  199. 0, &mlxplat_mux_data[i],
  200. sizeof(mlxplat_mux_data[i]));
  201. if (IS_ERR(priv->pdev_mux[i])) {
  202. err = PTR_ERR(priv->pdev_mux[i]);
  203. goto fail_platform_mux_register;
  204. }
  205. }
  206. return 0;
  207. fail_platform_mux_register:
  208. while (--i >= 0)
  209. platform_device_unregister(priv->pdev_mux[i]);
  210. platform_device_unregister(priv->pdev_i2c);
  211. fail_alloc:
  212. platform_device_unregister(mlxplat_dev);
  213. return err;
  214. }
  215. module_init(mlxplat_init);
  216. static void __exit mlxplat_exit(void)
  217. {
  218. struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
  219. int i;
  220. for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
  221. platform_device_unregister(priv->pdev_mux[i]);
  222. platform_device_unregister(priv->pdev_i2c);
  223. platform_device_unregister(mlxplat_dev);
  224. }
  225. module_exit(mlxplat_exit);
  226. MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
  227. MODULE_DESCRIPTION("Mellanox platform driver");
  228. MODULE_LICENSE("Dual BSD/GPL");
  229. MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:");
  230. MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:");
  231. MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:");
  232. MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:");
  233. MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:");