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 34 #include <linux/device.h> 35 #include <linux/dmi.h> 36 #include <linux/i2c.h> 37 #include <linux/i2c-mux.h> 38 #include <linux/io.h> 39 #include <linux/module.h> 40 #include <linux/platform_device.h> 41 #include <linux/platform_data/i2c-mux-reg.h> 42 #include <linux/platform_data/mlxreg.h> 43 #include <linux/regmap.h> 44 45 #define MLX_PLAT_DEVICE_NAME "mlxplat" 46 47 /* LPC bus IO offsets */ 48 #define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000 49 #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 50 #define MLXPLAT_CPLD_LPC_REG_LED1_OFFSET 0x20 51 #define MLXPLAT_CPLD_LPC_REG_LED2_OFFSET 0x21 52 #define MLXPLAT_CPLD_LPC_REG_LED3_OFFSET 0x22 53 #define MLXPLAT_CPLD_LPC_REG_LED4_OFFSET 0x23 54 #define MLXPLAT_CPLD_LPC_REG_LED5_OFFSET 0x24 55 #define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a 56 #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b 57 #define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40 58 #define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41 59 #define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58 60 #define MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET 0x59 61 #define MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET 0x5a 62 #define MLXPLAT_CPLD_LPC_REG_PWR_OFFSET 0x64 63 #define MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET 0x65 64 #define MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET 0x66 65 #define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88 66 #define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89 67 #define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a 68 #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 69 #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb 70 #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda 71 #define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL 72 #define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ 73 MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \ 74 MLXPLAT_CPLD_LPC_PIO_OFFSET) 75 #define MLXPLAT_CPLD_LPC_REG2 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ 76 MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \ 77 MLXPLAT_CPLD_LPC_PIO_OFFSET) 78 79 /* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */ 80 #define MLXPLAT_CPLD_AGGR_PSU_MASK_DEF 0x08 81 #define MLXPLAT_CPLD_AGGR_PWR_MASK_DEF 0x08 82 #define MLXPLAT_CPLD_AGGR_FAN_MASK_DEF 0x40 83 #define MLXPLAT_CPLD_AGGR_MASK_DEF (MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \ 84 MLXPLAT_CPLD_AGGR_FAN_MASK_DEF) 85 #define MLXPLAT_CPLD_AGGR_MASK_NG_DEF 0x04 86 #define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc0 87 #define MLXPLAT_CPLD_AGGR_MASK_MSN21XX 0x04 88 #define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0) 89 #define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0) 90 #define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0) 91 #define MLXPLAT_CPLD_FAN_NG_MASK GENMASK(5, 0) 92 #define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK GENMASK(7, 4) 93 #define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0) 94 95 /* Default I2C parent bus number */ 96 #define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1 97 98 /* Maximum number of possible physical buses equipped on system */ 99 #define MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM 16 100 101 /* Number of channels in group */ 102 #define MLXPLAT_CPLD_GRP_CHNL_NUM 8 103 104 /* Start channel numbers */ 105 #define MLXPLAT_CPLD_CH1 2 106 #define MLXPLAT_CPLD_CH2 10 107 108 /* Number of LPC attached MUX platform devices */ 109 #define MLXPLAT_CPLD_LPC_MUX_DEVS 2 110 111 /* Hotplug devices adapter numbers */ 112 #define MLXPLAT_CPLD_NR_NONE -1 113 #define MLXPLAT_CPLD_PSU_DEFAULT_NR 10 114 #define MLXPLAT_CPLD_PSU_MSNXXXX_NR 4 115 #define MLXPLAT_CPLD_FAN1_DEFAULT_NR 11 116 #define MLXPLAT_CPLD_FAN2_DEFAULT_NR 12 117 #define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13 118 #define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14 119 120 /* mlxplat_priv - platform private data 121 * @pdev_i2c - i2c controller platform device 122 * @pdev_mux - array of mux platform devices 123 * @pdev_hotplug - hotplug platform devices 124 * @pdev_led - led platform devices 125 */ 126 struct mlxplat_priv { 127 struct platform_device *pdev_i2c; 128 struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS]; 129 struct platform_device *pdev_hotplug; 130 struct platform_device *pdev_led; 131 }; 132 133 /* Regions for LPC I2C controller and LPC base register space */ 134 static const struct resource mlxplat_lpc_resources[] = { 135 [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR, 136 MLXPLAT_CPLD_LPC_IO_RANGE, 137 "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO), 138 [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR, 139 MLXPLAT_CPLD_LPC_IO_RANGE, 140 "mlxplat_cpld_lpc_regs", 141 IORESOURCE_IO), 142 }; 143 144 /* Platform default channels */ 145 static const int mlxplat_default_channels[][MLXPLAT_CPLD_GRP_CHNL_NUM] = { 146 { 147 MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2, 148 MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 + 149 5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7 150 }, 151 { 152 MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2, 153 MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 + 154 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7 155 }, 156 }; 157 158 /* Platform channels for MSN21xx system family */ 159 static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; 160 161 /* Platform mux data */ 162 static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = { 163 { 164 .parent = 1, 165 .base_nr = MLXPLAT_CPLD_CH1, 166 .write_only = 1, 167 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1, 168 .reg_size = 1, 169 .idle_in_use = 1, 170 }, 171 { 172 .parent = 1, 173 .base_nr = MLXPLAT_CPLD_CH2, 174 .write_only = 1, 175 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2, 176 .reg_size = 1, 177 .idle_in_use = 1, 178 }, 179 180 }; 181 182 /* Platform hotplug devices */ 183 static struct i2c_board_info mlxplat_mlxcpld_psu[] = { 184 { 185 I2C_BOARD_INFO("24c02", 0x51), 186 }, 187 { 188 I2C_BOARD_INFO("24c02", 0x50), 189 }, 190 }; 191 192 static struct i2c_board_info mlxplat_mlxcpld_ng_psu[] = { 193 { 194 I2C_BOARD_INFO("24c32", 0x51), 195 }, 196 { 197 I2C_BOARD_INFO("24c32", 0x50), 198 }, 199 }; 200 201 static struct i2c_board_info mlxplat_mlxcpld_pwr[] = { 202 { 203 I2C_BOARD_INFO("dps460", 0x59), 204 }, 205 { 206 I2C_BOARD_INFO("dps460", 0x58), 207 }, 208 }; 209 210 static struct i2c_board_info mlxplat_mlxcpld_fan[] = { 211 { 212 I2C_BOARD_INFO("24c32", 0x50), 213 }, 214 { 215 I2C_BOARD_INFO("24c32", 0x50), 216 }, 217 { 218 I2C_BOARD_INFO("24c32", 0x50), 219 }, 220 { 221 I2C_BOARD_INFO("24c32", 0x50), 222 }, 223 }; 224 225 /* Platform hotplug default data */ 226 static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = { 227 { 228 .label = "psu1", 229 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 230 .mask = BIT(0), 231 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0], 232 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, 233 }, 234 { 235 .label = "psu2", 236 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 237 .mask = BIT(1), 238 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1], 239 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, 240 }, 241 }; 242 243 static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = { 244 { 245 .label = "pwr1", 246 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 247 .mask = BIT(0), 248 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0], 249 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, 250 }, 251 { 252 .label = "pwr2", 253 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 254 .mask = BIT(1), 255 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1], 256 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, 257 }, 258 }; 259 260 static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = { 261 { 262 .label = "fan1", 263 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 264 .mask = BIT(0), 265 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0], 266 .hpdev.nr = MLXPLAT_CPLD_FAN1_DEFAULT_NR, 267 }, 268 { 269 .label = "fan2", 270 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 271 .mask = BIT(1), 272 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1], 273 .hpdev.nr = MLXPLAT_CPLD_FAN2_DEFAULT_NR, 274 }, 275 { 276 .label = "fan3", 277 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 278 .mask = BIT(2), 279 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2], 280 .hpdev.nr = MLXPLAT_CPLD_FAN3_DEFAULT_NR, 281 }, 282 { 283 .label = "fan4", 284 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 285 .mask = BIT(3), 286 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3], 287 .hpdev.nr = MLXPLAT_CPLD_FAN4_DEFAULT_NR, 288 }, 289 }; 290 291 static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = { 292 { 293 .data = mlxplat_mlxcpld_default_psu_items_data, 294 .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF, 295 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 296 .mask = MLXPLAT_CPLD_PSU_MASK, 297 .count = ARRAY_SIZE(mlxplat_mlxcpld_psu), 298 .inversed = 1, 299 .health = false, 300 }, 301 { 302 .data = mlxplat_mlxcpld_default_pwr_items_data, 303 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, 304 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 305 .mask = MLXPLAT_CPLD_PWR_MASK, 306 .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), 307 .inversed = 0, 308 .health = false, 309 }, 310 { 311 .data = mlxplat_mlxcpld_default_fan_items_data, 312 .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF, 313 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 314 .mask = MLXPLAT_CPLD_FAN_MASK, 315 .count = ARRAY_SIZE(mlxplat_mlxcpld_fan), 316 .inversed = 1, 317 .health = false, 318 }, 319 }; 320 321 static 322 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = { 323 .items = mlxplat_mlxcpld_default_items, 324 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items), 325 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 326 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, 327 }; 328 329 static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data[] = { 330 { 331 .label = "pwr1", 332 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 333 .mask = BIT(0), 334 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 335 }, 336 { 337 .label = "pwr2", 338 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 339 .mask = BIT(1), 340 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 341 }, 342 }; 343 344 /* Platform hotplug MSN21xx system family data */ 345 static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = { 346 { 347 .data = mlxplat_mlxcpld_msn21xx_pwr_items_data, 348 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, 349 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 350 .mask = MLXPLAT_CPLD_PWR_MASK, 351 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_pwr_items_data), 352 .inversed = 0, 353 .health = false, 354 }, 355 }; 356 357 static 358 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { 359 .items = mlxplat_mlxcpld_msn21xx_items, 360 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items), 361 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 362 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, 363 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, 364 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, 365 }; 366 367 /* Platform hotplug msn274x system family data */ 368 static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_psu_items_data[] = { 369 { 370 .label = "psu1", 371 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 372 .mask = BIT(0), 373 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0], 374 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, 375 }, 376 { 377 .label = "psu2", 378 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 379 .mask = BIT(1), 380 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1], 381 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, 382 }, 383 }; 384 385 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_pwr_items_data[] = { 386 { 387 .label = "pwr1", 388 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 389 .mask = BIT(0), 390 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0], 391 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, 392 }, 393 { 394 .label = "pwr2", 395 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 396 .mask = BIT(1), 397 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1], 398 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, 399 }, 400 }; 401 402 static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_fan_items_data[] = { 403 { 404 .label = "fan1", 405 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 406 .mask = BIT(0), 407 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 408 }, 409 { 410 .label = "fan2", 411 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 412 .mask = BIT(1), 413 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 414 }, 415 { 416 .label = "fan3", 417 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 418 .mask = BIT(2), 419 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 420 }, 421 { 422 .label = "fan4", 423 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 424 .mask = BIT(3), 425 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 426 }, 427 }; 428 429 static struct mlxreg_core_item mlxplat_mlxcpld_msn274x_items[] = { 430 { 431 .data = mlxplat_mlxcpld_msn274x_psu_items_data, 432 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 433 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 434 .mask = MLXPLAT_CPLD_PSU_MASK, 435 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_psu_items_data), 436 .inversed = 1, 437 .health = false, 438 }, 439 { 440 .data = mlxplat_mlxcpld_default_ng_pwr_items_data, 441 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 442 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 443 .mask = MLXPLAT_CPLD_PWR_MASK, 444 .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data), 445 .inversed = 0, 446 .health = false, 447 }, 448 { 449 .data = mlxplat_mlxcpld_msn274x_fan_items_data, 450 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 451 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 452 .mask = MLXPLAT_CPLD_FAN_MASK, 453 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_fan_items_data), 454 .inversed = 1, 455 .health = false, 456 }, 457 }; 458 459 static 460 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn274x_data = { 461 .items = mlxplat_mlxcpld_msn274x_items, 462 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_items), 463 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 464 .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 465 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, 466 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, 467 }; 468 469 /* Platform hotplug MSN201x system family data */ 470 static struct mlxreg_core_data mlxplat_mlxcpld_msn201x_pwr_items_data[] = { 471 { 472 .label = "pwr1", 473 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 474 .mask = BIT(0), 475 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 476 }, 477 { 478 .label = "pwr2", 479 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 480 .mask = BIT(1), 481 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 482 }, 483 }; 484 485 static struct mlxreg_core_item mlxplat_mlxcpld_msn201x_items[] = { 486 { 487 .data = mlxplat_mlxcpld_msn201x_pwr_items_data, 488 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, 489 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 490 .mask = MLXPLAT_CPLD_PWR_MASK, 491 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_pwr_items_data), 492 .inversed = 0, 493 .health = false, 494 }, 495 }; 496 497 static 498 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn201x_data = { 499 .items = mlxplat_mlxcpld_msn21xx_items, 500 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_items), 501 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 502 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, 503 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, 504 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, 505 }; 506 507 /* Platform hotplug next generation system family data */ 508 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_psu_items_data[] = { 509 { 510 .label = "psu1", 511 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 512 .mask = BIT(0), 513 .hpdev.brdinfo = &mlxplat_mlxcpld_ng_psu[0], 514 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, 515 }, 516 { 517 .label = "psu2", 518 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 519 .mask = BIT(1), 520 .hpdev.brdinfo = &mlxplat_mlxcpld_ng_psu[1], 521 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, 522 }, 523 }; 524 525 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_fan_items_data[] = { 526 { 527 .label = "fan1", 528 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 529 .mask = BIT(0), 530 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 531 }, 532 { 533 .label = "fan2", 534 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 535 .mask = BIT(1), 536 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 537 }, 538 { 539 .label = "fan3", 540 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 541 .mask = BIT(2), 542 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 543 }, 544 { 545 .label = "fan4", 546 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 547 .mask = BIT(3), 548 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 549 }, 550 { 551 .label = "fan5", 552 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 553 .mask = BIT(4), 554 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 555 }, 556 { 557 .label = "fan6", 558 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 559 .mask = BIT(5), 560 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 561 }, 562 }; 563 564 static struct mlxreg_core_item mlxplat_mlxcpld_default_ng_items[] = { 565 { 566 .data = mlxplat_mlxcpld_default_ng_psu_items_data, 567 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 568 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 569 .mask = MLXPLAT_CPLD_PSU_MASK, 570 .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_psu_items_data), 571 .inversed = 1, 572 .health = false, 573 }, 574 { 575 .data = mlxplat_mlxcpld_default_ng_pwr_items_data, 576 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 577 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 578 .mask = MLXPLAT_CPLD_PWR_MASK, 579 .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data), 580 .inversed = 0, 581 .health = false, 582 }, 583 { 584 .data = mlxplat_mlxcpld_default_ng_fan_items_data, 585 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 586 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 587 .mask = MLXPLAT_CPLD_FAN_NG_MASK, 588 .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data), 589 .inversed = 1, 590 .health = false, 591 }, 592 }; 593 594 static 595 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { 596 .items = mlxplat_mlxcpld_default_ng_items, 597 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_items), 598 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 599 .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 600 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, 601 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, 602 }; 603 604 /* Platform led default data */ 605 static struct mlxreg_core_data mlxplat_mlxcpld_default_led_data[] = { 606 { 607 .label = "status:green", 608 .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, 609 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 610 }, 611 { 612 .label = "status:red", 613 .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, 614 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK 615 }, 616 { 617 .label = "psu:green", 618 .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, 619 .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 620 }, 621 { 622 .label = "psu:red", 623 .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, 624 .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 625 }, 626 { 627 .label = "fan1:green", 628 .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, 629 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 630 }, 631 { 632 .label = "fan1:red", 633 .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, 634 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 635 }, 636 { 637 .label = "fan2:green", 638 .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, 639 .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 640 }, 641 { 642 .label = "fan2:red", 643 .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, 644 .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 645 }, 646 { 647 .label = "fan3:green", 648 .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, 649 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 650 }, 651 { 652 .label = "fan3:red", 653 .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, 654 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 655 }, 656 { 657 .label = "fan4:green", 658 .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, 659 .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 660 }, 661 { 662 .label = "fan4:red", 663 .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, 664 .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 665 }, 666 }; 667 668 static struct mlxreg_core_platform_data mlxplat_default_led_data = { 669 .data = mlxplat_mlxcpld_default_led_data, 670 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_led_data), 671 }; 672 673 /* Platform led MSN21xx system family data */ 674 static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_led_data[] = { 675 { 676 .label = "status:green", 677 .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, 678 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 679 }, 680 { 681 .label = "status:red", 682 .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, 683 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK 684 }, 685 { 686 .label = "fan:green", 687 .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, 688 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 689 }, 690 { 691 .label = "fan:red", 692 .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, 693 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 694 }, 695 { 696 .label = "psu1:green", 697 .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, 698 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 699 }, 700 { 701 .label = "psu1:red", 702 .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, 703 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 704 }, 705 { 706 .label = "psu2:green", 707 .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, 708 .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 709 }, 710 { 711 .label = "psu2:red", 712 .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, 713 .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 714 }, 715 { 716 .label = "uid:blue", 717 .reg = MLXPLAT_CPLD_LPC_REG_LED5_OFFSET, 718 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 719 }, 720 }; 721 722 static struct mlxreg_core_platform_data mlxplat_msn21xx_led_data = { 723 .data = mlxplat_mlxcpld_msn21xx_led_data, 724 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_led_data), 725 }; 726 727 /* Platform led for default data for 200GbE systems */ 728 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_led_data[] = { 729 { 730 .label = "status:green", 731 .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, 732 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 733 }, 734 { 735 .label = "status:orange", 736 .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, 737 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK 738 }, 739 { 740 .label = "psu:green", 741 .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, 742 .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 743 }, 744 { 745 .label = "psu:orange", 746 .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, 747 .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 748 }, 749 { 750 .label = "fan1:green", 751 .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, 752 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 753 }, 754 { 755 .label = "fan1:orange", 756 .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, 757 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 758 }, 759 { 760 .label = "fan2:green", 761 .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, 762 .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 763 }, 764 { 765 .label = "fan2:orange", 766 .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, 767 .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 768 }, 769 { 770 .label = "fan3:green", 771 .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, 772 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 773 }, 774 { 775 .label = "fan3:orange", 776 .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, 777 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 778 }, 779 { 780 .label = "fan4:green", 781 .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, 782 .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 783 }, 784 { 785 .label = "fan4:orange", 786 .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, 787 .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 788 }, 789 { 790 .label = "fan5:green", 791 .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, 792 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 793 }, 794 { 795 .label = "fan5:orange", 796 .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, 797 .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 798 }, 799 { 800 .label = "fan6:green", 801 .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, 802 .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 803 }, 804 { 805 .label = "fan6:orange", 806 .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, 807 .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 808 }, 809 }; 810 811 static struct mlxreg_core_platform_data mlxplat_default_ng_led_data = { 812 .data = mlxplat_mlxcpld_default_ng_led_data, 813 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_led_data), 814 }; 815 816 817 static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) 818 { 819 switch (reg) { 820 case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: 821 case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: 822 case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: 823 case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: 824 case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: 825 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: 826 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: 827 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: 828 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: 829 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: 830 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: 831 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: 832 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: 833 return true; 834 } 835 return false; 836 } 837 838 static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) 839 { 840 switch (reg) { 841 case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: 842 case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: 843 case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: 844 case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: 845 case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: 846 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: 847 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: 848 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: 849 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: 850 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: 851 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: 852 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: 853 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET: 854 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: 855 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: 856 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: 857 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: 858 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: 859 return true; 860 } 861 return false; 862 } 863 864 static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) 865 { 866 switch (reg) { 867 case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: 868 case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: 869 case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: 870 case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: 871 case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: 872 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: 873 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: 874 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: 875 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: 876 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: 877 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: 878 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: 879 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET: 880 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: 881 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: 882 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: 883 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: 884 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: 885 return true; 886 } 887 return false; 888 } 889 890 struct mlxplat_mlxcpld_regmap_context { 891 void __iomem *base; 892 }; 893 894 static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx; 895 896 static int 897 mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val) 898 { 899 struct mlxplat_mlxcpld_regmap_context *ctx = context; 900 901 *val = ioread8(ctx->base + reg); 902 return 0; 903 } 904 905 static int 906 mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val) 907 { 908 struct mlxplat_mlxcpld_regmap_context *ctx = context; 909 910 iowrite8(val, ctx->base + reg); 911 return 0; 912 } 913 914 static const struct regmap_config mlxplat_mlxcpld_regmap_config = { 915 .reg_bits = 8, 916 .val_bits = 8, 917 .max_register = 255, 918 .cache_type = REGCACHE_FLAT, 919 .writeable_reg = mlxplat_mlxcpld_writeable_reg, 920 .readable_reg = mlxplat_mlxcpld_readable_reg, 921 .volatile_reg = mlxplat_mlxcpld_volatile_reg, 922 .reg_read = mlxplat_mlxcpld_reg_read, 923 .reg_write = mlxplat_mlxcpld_reg_write, 924 }; 925 926 static struct resource mlxplat_mlxcpld_resources[] = { 927 [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"), 928 }; 929 930 static struct platform_device *mlxplat_dev; 931 static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; 932 static struct mlxreg_core_platform_data *mlxplat_led; 933 934 static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) 935 { 936 int i; 937 938 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { 939 mlxplat_mux_data[i].values = mlxplat_default_channels[i]; 940 mlxplat_mux_data[i].n_values = 941 ARRAY_SIZE(mlxplat_default_channels[i]); 942 } 943 mlxplat_hotplug = &mlxplat_mlxcpld_default_data; 944 mlxplat_hotplug->deferred_nr = 945 mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; 946 mlxplat_led = &mlxplat_default_led_data; 947 948 return 1; 949 }; 950 951 static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) 952 { 953 int i; 954 955 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { 956 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; 957 mlxplat_mux_data[i].n_values = 958 ARRAY_SIZE(mlxplat_msn21xx_channels); 959 } 960 mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data; 961 mlxplat_hotplug->deferred_nr = 962 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; 963 mlxplat_led = &mlxplat_msn21xx_led_data; 964 965 return 1; 966 }; 967 968 static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) 969 { 970 int i; 971 972 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { 973 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; 974 mlxplat_mux_data[i].n_values = 975 ARRAY_SIZE(mlxplat_msn21xx_channels); 976 } 977 mlxplat_hotplug = &mlxplat_mlxcpld_msn274x_data; 978 mlxplat_hotplug->deferred_nr = 979 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; 980 mlxplat_led = &mlxplat_default_led_data; 981 982 return 1; 983 }; 984 985 static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) 986 { 987 int i; 988 989 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { 990 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; 991 mlxplat_mux_data[i].n_values = 992 ARRAY_SIZE(mlxplat_msn21xx_channels); 993 } 994 mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data; 995 mlxplat_hotplug->deferred_nr = 996 mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; 997 mlxplat_led = &mlxplat_default_ng_led_data; 998 999 return 1; 1000 }; 1001 1002 static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) 1003 { 1004 int i; 1005 1006 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { 1007 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; 1008 mlxplat_mux_data[i].n_values = 1009 ARRAY_SIZE(mlxplat_msn21xx_channels); 1010 } 1011 mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data; 1012 mlxplat_hotplug->deferred_nr = 1013 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; 1014 mlxplat_led = &mlxplat_msn21xx_led_data; 1015 1016 return 1; 1017 }; 1018 1019 static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { 1020 { 1021 .callback = mlxplat_dmi_msn274x_matched, 1022 .matches = { 1023 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 1024 DMI_MATCH(DMI_PRODUCT_NAME, "MSN274"), 1025 }, 1026 }, 1027 { 1028 .callback = mlxplat_dmi_default_matched, 1029 .matches = { 1030 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 1031 DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"), 1032 }, 1033 }, 1034 { 1035 .callback = mlxplat_dmi_default_matched, 1036 .matches = { 1037 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 1038 DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"), 1039 }, 1040 }, 1041 { 1042 .callback = mlxplat_dmi_default_matched, 1043 .matches = { 1044 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 1045 DMI_MATCH(DMI_PRODUCT_NAME, "MSB"), 1046 }, 1047 }, 1048 { 1049 .callback = mlxplat_dmi_default_matched, 1050 .matches = { 1051 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 1052 DMI_MATCH(DMI_PRODUCT_NAME, "MSX"), 1053 }, 1054 }, 1055 { 1056 .callback = mlxplat_dmi_msn21xx_matched, 1057 .matches = { 1058 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 1059 DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"), 1060 }, 1061 }, 1062 { 1063 .callback = mlxplat_dmi_msn201x_matched, 1064 .matches = { 1065 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 1066 DMI_MATCH(DMI_PRODUCT_NAME, "MSN201"), 1067 }, 1068 }, 1069 { 1070 .callback = mlxplat_dmi_qmb7xx_matched, 1071 .matches = { 1072 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 1073 DMI_MATCH(DMI_PRODUCT_NAME, "QMB7"), 1074 }, 1075 }, 1076 { 1077 .callback = mlxplat_dmi_qmb7xx_matched, 1078 .matches = { 1079 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 1080 DMI_MATCH(DMI_PRODUCT_NAME, "SN37"), 1081 }, 1082 }, 1083 { 1084 .callback = mlxplat_dmi_qmb7xx_matched, 1085 .matches = { 1086 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 1087 DMI_MATCH(DMI_PRODUCT_NAME, "SN34"), 1088 }, 1089 }, 1090 { 1091 .callback = mlxplat_dmi_default_matched, 1092 .matches = { 1093 DMI_MATCH(DMI_BOARD_NAME, "VMOD0001"), 1094 }, 1095 }, 1096 { 1097 .callback = mlxplat_dmi_msn21xx_matched, 1098 .matches = { 1099 DMI_MATCH(DMI_BOARD_NAME, "VMOD0002"), 1100 }, 1101 }, 1102 { 1103 .callback = mlxplat_dmi_msn274x_matched, 1104 .matches = { 1105 DMI_MATCH(DMI_BOARD_NAME, "VMOD0003"), 1106 }, 1107 }, 1108 { 1109 .callback = mlxplat_dmi_msn201x_matched, 1110 .matches = { 1111 DMI_MATCH(DMI_BOARD_NAME, "VMOD0004"), 1112 }, 1113 }, 1114 { 1115 .callback = mlxplat_dmi_qmb7xx_matched, 1116 .matches = { 1117 DMI_MATCH(DMI_BOARD_NAME, "VMOD0005"), 1118 }, 1119 }, 1120 { } 1121 }; 1122 1123 MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table); 1124 1125 static int mlxplat_mlxcpld_verify_bus_topology(int *nr) 1126 { 1127 struct i2c_adapter *search_adap; 1128 int shift, i; 1129 1130 /* Scan adapters from expected id to verify it is free. */ 1131 *nr = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; 1132 for (i = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; i < 1133 MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; i++) { 1134 search_adap = i2c_get_adapter(i); 1135 if (search_adap) { 1136 i2c_put_adapter(search_adap); 1137 continue; 1138 } 1139 1140 /* Return if expected parent adapter is free. */ 1141 if (i == MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR) 1142 return 0; 1143 break; 1144 } 1145 1146 /* Return with error if free id for adapter is not found. */ 1147 if (i == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) 1148 return -ENODEV; 1149 1150 /* Shift adapter ids, since expected parent adapter is not free. */ 1151 *nr = i; 1152 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { 1153 shift = *nr - mlxplat_mux_data[i].parent; 1154 mlxplat_mux_data[i].parent = *nr; 1155 mlxplat_mux_data[i].base_nr += shift; 1156 if (shift > 0) 1157 mlxplat_hotplug->shift_nr = shift; 1158 } 1159 1160 return 0; 1161 } 1162 1163 static int __init mlxplat_init(void) 1164 { 1165 struct mlxplat_priv *priv; 1166 int i, nr, err; 1167 1168 if (!dmi_check_system(mlxplat_dmi_table)) 1169 return -ENODEV; 1170 1171 mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1, 1172 mlxplat_lpc_resources, 1173 ARRAY_SIZE(mlxplat_lpc_resources)); 1174 1175 if (IS_ERR(mlxplat_dev)) 1176 return PTR_ERR(mlxplat_dev); 1177 1178 priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv), 1179 GFP_KERNEL); 1180 if (!priv) { 1181 err = -ENOMEM; 1182 goto fail_alloc; 1183 } 1184 platform_set_drvdata(mlxplat_dev, priv); 1185 1186 err = mlxplat_mlxcpld_verify_bus_topology(&nr); 1187 if (nr < 0) 1188 goto fail_alloc; 1189 1190 nr = (nr == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) ? -1 : nr; 1191 priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", nr, 1192 NULL, 0); 1193 if (IS_ERR(priv->pdev_i2c)) { 1194 err = PTR_ERR(priv->pdev_i2c); 1195 goto fail_alloc; 1196 } 1197 1198 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { 1199 priv->pdev_mux[i] = platform_device_register_resndata( 1200 &mlxplat_dev->dev, 1201 "i2c-mux-reg", i, NULL, 1202 0, &mlxplat_mux_data[i], 1203 sizeof(mlxplat_mux_data[i])); 1204 if (IS_ERR(priv->pdev_mux[i])) { 1205 err = PTR_ERR(priv->pdev_mux[i]); 1206 goto fail_platform_mux_register; 1207 } 1208 } 1209 1210 mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev, 1211 mlxplat_lpc_resources[1].start, 1); 1212 if (!mlxplat_mlxcpld_regmap_ctx.base) { 1213 err = -ENOMEM; 1214 goto fail_platform_mux_register; 1215 } 1216 1217 mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL, 1218 &mlxplat_mlxcpld_regmap_ctx, 1219 &mlxplat_mlxcpld_regmap_config); 1220 if (IS_ERR(mlxplat_hotplug->regmap)) { 1221 err = PTR_ERR(mlxplat_hotplug->regmap); 1222 goto fail_platform_mux_register; 1223 } 1224 1225 priv->pdev_hotplug = platform_device_register_resndata( 1226 &mlxplat_dev->dev, "mlxreg-hotplug", 1227 PLATFORM_DEVID_NONE, 1228 mlxplat_mlxcpld_resources, 1229 ARRAY_SIZE(mlxplat_mlxcpld_resources), 1230 mlxplat_hotplug, sizeof(*mlxplat_hotplug)); 1231 if (IS_ERR(priv->pdev_hotplug)) { 1232 err = PTR_ERR(priv->pdev_hotplug); 1233 goto fail_platform_mux_register; 1234 } 1235 1236 /* Add LED driver. */ 1237 mlxplat_led->regmap = mlxplat_hotplug->regmap; 1238 priv->pdev_led = platform_device_register_resndata( 1239 &mlxplat_dev->dev, "leds-mlxreg", 1240 PLATFORM_DEVID_NONE, NULL, 0, 1241 mlxplat_led, sizeof(*mlxplat_led)); 1242 if (IS_ERR(priv->pdev_led)) { 1243 err = PTR_ERR(priv->pdev_led); 1244 goto fail_platform_hotplug_register; 1245 } 1246 1247 /* Sync registers with hardware. */ 1248 regcache_mark_dirty(mlxplat_hotplug->regmap); 1249 err = regcache_sync(mlxplat_hotplug->regmap); 1250 if (err) 1251 goto fail_platform_led_register; 1252 1253 return 0; 1254 1255 fail_platform_led_register: 1256 platform_device_unregister(priv->pdev_led); 1257 fail_platform_hotplug_register: 1258 platform_device_unregister(priv->pdev_hotplug); 1259 fail_platform_mux_register: 1260 while (--i >= 0) 1261 platform_device_unregister(priv->pdev_mux[i]); 1262 platform_device_unregister(priv->pdev_i2c); 1263 fail_alloc: 1264 platform_device_unregister(mlxplat_dev); 1265 1266 return err; 1267 } 1268 module_init(mlxplat_init); 1269 1270 static void __exit mlxplat_exit(void) 1271 { 1272 struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); 1273 int i; 1274 1275 platform_device_unregister(priv->pdev_led); 1276 platform_device_unregister(priv->pdev_hotplug); 1277 1278 for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--) 1279 platform_device_unregister(priv->pdev_mux[i]); 1280 1281 platform_device_unregister(priv->pdev_i2c); 1282 platform_device_unregister(mlxplat_dev); 1283 } 1284 module_exit(mlxplat_exit); 1285 1286 MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)"); 1287 MODULE_DESCRIPTION("Mellanox platform driver"); 1288 MODULE_LICENSE("Dual BSD/GPL"); 1289