• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
35 #include <linux/device.h>
36 #include <linux/dmi.h>
37 #include <linux/i2c.h>
38 #include <linux/i2c-mux.h>
39 #include <linux/module.h>
40 #include <linux/platform_device.h>
41 #include <linux/platform_data/i2c-mux-reg.h>
42 
43 #define MLX_PLAT_DEVICE_NAME		"mlxplat"
44 
45 /* LPC bus IO offsets */
46 #define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR		0x2000
47 #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR		0x2500
48 #define MLXPLAT_CPLD_LPC_IO_RANGE		0x100
49 #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF		0xdb
50 #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF		0xda
51 #define MLXPLAT_CPLD_LPC_PIO_OFFSET		0x10000UL
52 #define MLXPLAT_CPLD_LPC_REG1	((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
53 				  MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \
54 				  MLXPLAT_CPLD_LPC_PIO_OFFSET)
55 #define MLXPLAT_CPLD_LPC_REG2	((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
56 				  MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \
57 				  MLXPLAT_CPLD_LPC_PIO_OFFSET)
58 
59 /* Start channel numbers */
60 #define MLXPLAT_CPLD_CH1			2
61 #define MLXPLAT_CPLD_CH2			10
62 
63 /* Number of LPC attached MUX platform devices */
64 #define MLXPLAT_CPLD_LPC_MUX_DEVS		2
65 
66 /* mlxplat_priv - platform private data
67  * @pdev_i2c - i2c controller platform device
68  * @pdev_mux - array of mux platform devices
69  */
70 struct mlxplat_priv {
71 	struct platform_device *pdev_i2c;
72 	struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
73 };
74 
75 /* Regions for LPC I2C controller and LPC base register space */
76 static const struct resource mlxplat_lpc_resources[] = {
77 	[0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
78 			       MLXPLAT_CPLD_LPC_IO_RANGE,
79 			       "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO),
80 	[1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR,
81 			       MLXPLAT_CPLD_LPC_IO_RANGE,
82 			       "mlxplat_cpld_lpc_regs",
83 			       IORESOURCE_IO),
84 };
85 
86 /* Platform default channels */
87 static const int mlxplat_default_channels[][8] = {
88 	{
89 		MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
90 		MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
91 		5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7
92 	},
93 	{
94 		MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2,
95 		MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 +
96 		5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7
97 	},
98 };
99 
100 /* Platform channels for MSN21xx system family */
101 static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
102 
103 /* Platform mux data */
104 static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
105 	{
106 		.parent = 1,
107 		.base_nr = MLXPLAT_CPLD_CH1,
108 		.write_only = 1,
109 		.reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
110 		.reg_size = 1,
111 		.idle_in_use = 1,
112 	},
113 	{
114 		.parent = 1,
115 		.base_nr = MLXPLAT_CPLD_CH2,
116 		.write_only = 1,
117 		.reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
118 		.reg_size = 1,
119 		.idle_in_use = 1,
120 	},
121 
122 };
123 
124 static struct platform_device *mlxplat_dev;
125 
mlxplat_dmi_default_matched(const struct dmi_system_id * dmi)126 static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
127 {
128 	int i;
129 
130 	for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
131 		mlxplat_mux_data[i].values = mlxplat_default_channels[i];
132 		mlxplat_mux_data[i].n_values =
133 				ARRAY_SIZE(mlxplat_default_channels[i]);
134 	}
135 
136 	return 1;
137 };
138 
mlxplat_dmi_msn21xx_matched(const struct dmi_system_id * dmi)139 static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
140 {
141 	int i;
142 
143 	for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
144 		mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
145 		mlxplat_mux_data[i].n_values =
146 				ARRAY_SIZE(mlxplat_msn21xx_channels);
147 	}
148 
149 	return 1;
150 };
151 
152 static struct dmi_system_id mlxplat_dmi_table[] __initdata = {
153 	{
154 		.callback = mlxplat_dmi_default_matched,
155 		.matches = {
156 			DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
157 			DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
158 		},
159 	},
160 	{
161 		.callback = mlxplat_dmi_default_matched,
162 		.matches = {
163 			DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
164 			DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
165 		},
166 	},
167 	{
168 		.callback = mlxplat_dmi_default_matched,
169 		.matches = {
170 			DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
171 			DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
172 		},
173 	},
174 	{
175 		.callback = mlxplat_dmi_default_matched,
176 		.matches = {
177 			DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
178 			DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
179 		},
180 	},
181 	{
182 		.callback = mlxplat_dmi_msn21xx_matched,
183 		.matches = {
184 			DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
185 			DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
186 		},
187 	},
188 	{ }
189 };
190 
mlxplat_init(void)191 static int __init mlxplat_init(void)
192 {
193 	struct mlxplat_priv *priv;
194 	int i, err;
195 
196 	if (!dmi_check_system(mlxplat_dmi_table))
197 		return -ENODEV;
198 
199 	mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
200 					mlxplat_lpc_resources,
201 					ARRAY_SIZE(mlxplat_lpc_resources));
202 
203 	if (IS_ERR(mlxplat_dev))
204 		return PTR_ERR(mlxplat_dev);
205 
206 	priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
207 			    GFP_KERNEL);
208 	if (!priv) {
209 		err = -ENOMEM;
210 		goto fail_alloc;
211 	}
212 	platform_set_drvdata(mlxplat_dev, priv);
213 
214 	priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1,
215 							 NULL, 0);
216 	if (IS_ERR(priv->pdev_i2c)) {
217 		err = PTR_ERR(priv->pdev_i2c);
218 		goto fail_alloc;
219 	};
220 
221 	for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
222 		priv->pdev_mux[i] = platform_device_register_resndata(
223 						&mlxplat_dev->dev,
224 						"i2c-mux-reg", i, NULL,
225 						0, &mlxplat_mux_data[i],
226 						sizeof(mlxplat_mux_data[i]));
227 		if (IS_ERR(priv->pdev_mux[i])) {
228 			err = PTR_ERR(priv->pdev_mux[i]);
229 			goto fail_platform_mux_register;
230 		}
231 	}
232 
233 	return 0;
234 
235 fail_platform_mux_register:
236 	while (--i >= 0)
237 		platform_device_unregister(priv->pdev_mux[i]);
238 	platform_device_unregister(priv->pdev_i2c);
239 fail_alloc:
240 	platform_device_unregister(mlxplat_dev);
241 
242 	return err;
243 }
244 module_init(mlxplat_init);
245 
mlxplat_exit(void)246 static void __exit mlxplat_exit(void)
247 {
248 	struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
249 	int i;
250 
251 	for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
252 		platform_device_unregister(priv->pdev_mux[i]);
253 
254 	platform_device_unregister(priv->pdev_i2c);
255 	platform_device_unregister(mlxplat_dev);
256 }
257 module_exit(mlxplat_exit);
258 
259 MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
260 MODULE_DESCRIPTION("Mellanox platform driver");
261 MODULE_LICENSE("Dual BSD/GPL");
262 MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:");
263 MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:");
264 MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:");
265 MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:");
266 MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:");
267