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_AGGR_OFFSET 0x3a 51 #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b 52 #define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40 53 #define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41 54 #define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58 55 #define MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET 0x59 56 #define MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET 0x5a 57 #define MLXPLAT_CPLD_LPC_REG_PWR_OFFSET 0x64 58 #define MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET 0x65 59 #define MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET 0x66 60 #define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88 61 #define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89 62 #define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a 63 #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 64 #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb 65 #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda 66 #define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL 67 #define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ 68 MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \ 69 MLXPLAT_CPLD_LPC_PIO_OFFSET) 70 #define MLXPLAT_CPLD_LPC_REG2 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ 71 MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \ 72 MLXPLAT_CPLD_LPC_PIO_OFFSET) 73 74 /* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */ 75 #define MLXPLAT_CPLD_AGGR_PSU_MASK_DEF 0x08 76 #define MLXPLAT_CPLD_AGGR_PWR_MASK_DEF 0x08 77 #define MLXPLAT_CPLD_AGGR_FAN_MASK_DEF 0x40 78 #define MLXPLAT_CPLD_AGGR_MASK_DEF (MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \ 79 MLXPLAT_CPLD_AGGR_FAN_MASK_DEF) 80 #define MLXPLAT_CPLD_AGGR_MASK_NG_DEF 0x04 81 #define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc0 82 #define MLXPLAT_CPLD_AGGR_MASK_MSN21XX 0x04 83 #define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0) 84 #define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0) 85 #define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0) 86 #define MLXPLAT_CPLD_FAN_NG_MASK GENMASK(5, 0) 87 88 /* Default I2C parent bus number */ 89 #define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1 90 91 /* Maximum number of possible physical buses equipped on system */ 92 #define MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM 16 93 94 /* Number of channels in group */ 95 #define MLXPLAT_CPLD_GRP_CHNL_NUM 8 96 97 /* Start channel numbers */ 98 #define MLXPLAT_CPLD_CH1 2 99 #define MLXPLAT_CPLD_CH2 10 100 101 /* Number of LPC attached MUX platform devices */ 102 #define MLXPLAT_CPLD_LPC_MUX_DEVS 2 103 104 /* Hotplug devices adapter numbers */ 105 #define MLXPLAT_CPLD_NR_NONE -1 106 #define MLXPLAT_CPLD_PSU_DEFAULT_NR 10 107 #define MLXPLAT_CPLD_PSU_MSNXXXX_NR 4 108 #define MLXPLAT_CPLD_FAN1_DEFAULT_NR 11 109 #define MLXPLAT_CPLD_FAN2_DEFAULT_NR 12 110 #define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13 111 #define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14 112 113 /* mlxplat_priv - platform private data 114 * @pdev_i2c - i2c controller platform device 115 * @pdev_mux - array of mux platform devices 116 * @pdev_hotplug - hotplug platform devices 117 */ 118 struct mlxplat_priv { 119 struct platform_device *pdev_i2c; 120 struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS]; 121 struct platform_device *pdev_hotplug; 122 }; 123 124 /* Regions for LPC I2C controller and LPC base register space */ 125 static const struct resource mlxplat_lpc_resources[] = { 126 [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR, 127 MLXPLAT_CPLD_LPC_IO_RANGE, 128 "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO), 129 [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR, 130 MLXPLAT_CPLD_LPC_IO_RANGE, 131 "mlxplat_cpld_lpc_regs", 132 IORESOURCE_IO), 133 }; 134 135 /* Platform default channels */ 136 static const int mlxplat_default_channels[][MLXPLAT_CPLD_GRP_CHNL_NUM] = { 137 { 138 MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2, 139 MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 + 140 5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7 141 }, 142 { 143 MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2, 144 MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 + 145 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7 146 }, 147 }; 148 149 /* Platform channels for MSN21xx system family */ 150 static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; 151 152 /* Platform mux data */ 153 static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = { 154 { 155 .parent = 1, 156 .base_nr = MLXPLAT_CPLD_CH1, 157 .write_only = 1, 158 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1, 159 .reg_size = 1, 160 .idle_in_use = 1, 161 }, 162 { 163 .parent = 1, 164 .base_nr = MLXPLAT_CPLD_CH2, 165 .write_only = 1, 166 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2, 167 .reg_size = 1, 168 .idle_in_use = 1, 169 }, 170 171 }; 172 173 /* Platform hotplug devices */ 174 static struct i2c_board_info mlxplat_mlxcpld_psu[] = { 175 { 176 I2C_BOARD_INFO("24c02", 0x51), 177 }, 178 { 179 I2C_BOARD_INFO("24c02", 0x50), 180 }, 181 }; 182 183 static struct i2c_board_info mlxplat_mlxcpld_ng_psu[] = { 184 { 185 I2C_BOARD_INFO("24c32", 0x51), 186 }, 187 { 188 I2C_BOARD_INFO("24c32", 0x50), 189 }, 190 }; 191 192 static struct i2c_board_info mlxplat_mlxcpld_pwr[] = { 193 { 194 I2C_BOARD_INFO("dps460", 0x59), 195 }, 196 { 197 I2C_BOARD_INFO("dps460", 0x58), 198 }, 199 }; 200 201 static struct i2c_board_info mlxplat_mlxcpld_fan[] = { 202 { 203 I2C_BOARD_INFO("24c32", 0x50), 204 }, 205 { 206 I2C_BOARD_INFO("24c32", 0x50), 207 }, 208 { 209 I2C_BOARD_INFO("24c32", 0x50), 210 }, 211 { 212 I2C_BOARD_INFO("24c32", 0x50), 213 }, 214 }; 215 216 /* Platform hotplug default data */ 217 static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = { 218 { 219 .label = "psu1", 220 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 221 .mask = BIT(0), 222 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0], 223 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, 224 }, 225 { 226 .label = "psu2", 227 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 228 .mask = BIT(1), 229 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1], 230 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, 231 }, 232 }; 233 234 static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = { 235 { 236 .label = "pwr1", 237 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 238 .mask = BIT(0), 239 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0], 240 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, 241 }, 242 { 243 .label = "pwr2", 244 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 245 .mask = BIT(1), 246 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1], 247 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, 248 }, 249 }; 250 251 static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = { 252 { 253 .label = "fan1", 254 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 255 .mask = BIT(0), 256 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0], 257 .hpdev.nr = MLXPLAT_CPLD_FAN1_DEFAULT_NR, 258 }, 259 { 260 .label = "fan2", 261 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 262 .mask = BIT(1), 263 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1], 264 .hpdev.nr = MLXPLAT_CPLD_FAN2_DEFAULT_NR, 265 }, 266 { 267 .label = "fan3", 268 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 269 .mask = BIT(2), 270 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2], 271 .hpdev.nr = MLXPLAT_CPLD_FAN3_DEFAULT_NR, 272 }, 273 { 274 .label = "fan4", 275 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 276 .mask = BIT(3), 277 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3], 278 .hpdev.nr = MLXPLAT_CPLD_FAN4_DEFAULT_NR, 279 }, 280 }; 281 282 static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = { 283 { 284 .data = mlxplat_mlxcpld_default_psu_items_data, 285 .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF, 286 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 287 .mask = MLXPLAT_CPLD_PSU_MASK, 288 .count = ARRAY_SIZE(mlxplat_mlxcpld_psu), 289 .inversed = 1, 290 .health = false, 291 }, 292 { 293 .data = mlxplat_mlxcpld_default_pwr_items_data, 294 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, 295 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 296 .mask = MLXPLAT_CPLD_PWR_MASK, 297 .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), 298 .inversed = 0, 299 .health = false, 300 }, 301 { 302 .data = mlxplat_mlxcpld_default_fan_items_data, 303 .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF, 304 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 305 .mask = MLXPLAT_CPLD_FAN_MASK, 306 .count = ARRAY_SIZE(mlxplat_mlxcpld_fan), 307 .inversed = 1, 308 .health = false, 309 }, 310 }; 311 312 static 313 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = { 314 .items = mlxplat_mlxcpld_default_items, 315 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items), 316 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 317 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, 318 }; 319 320 static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data[] = { 321 { 322 .label = "pwr1", 323 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 324 .mask = BIT(0), 325 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 326 }, 327 { 328 .label = "pwr2", 329 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 330 .mask = BIT(1), 331 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 332 }, 333 }; 334 335 /* Platform hotplug MSN21xx system family data */ 336 static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = { 337 { 338 .data = mlxplat_mlxcpld_msn21xx_pwr_items_data, 339 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, 340 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 341 .mask = MLXPLAT_CPLD_PWR_MASK, 342 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_pwr_items_data), 343 .inversed = 0, 344 .health = false, 345 }, 346 }; 347 348 static 349 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { 350 .items = mlxplat_mlxcpld_msn21xx_items, 351 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items), 352 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 353 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, 354 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, 355 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, 356 }; 357 358 /* Platform hotplug msn274x system family data */ 359 static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_psu_items_data[] = { 360 { 361 .label = "psu1", 362 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 363 .mask = BIT(0), 364 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0], 365 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, 366 }, 367 { 368 .label = "psu2", 369 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 370 .mask = BIT(1), 371 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1], 372 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, 373 }, 374 }; 375 376 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_pwr_items_data[] = { 377 { 378 .label = "pwr1", 379 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 380 .mask = BIT(0), 381 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0], 382 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, 383 }, 384 { 385 .label = "pwr2", 386 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 387 .mask = BIT(1), 388 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1], 389 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, 390 }, 391 }; 392 393 static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_fan_items_data[] = { 394 { 395 .label = "fan1", 396 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 397 .mask = BIT(0), 398 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 399 }, 400 { 401 .label = "fan2", 402 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 403 .mask = BIT(1), 404 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 405 }, 406 { 407 .label = "fan3", 408 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 409 .mask = BIT(2), 410 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 411 }, 412 { 413 .label = "fan4", 414 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 415 .mask = BIT(3), 416 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 417 }, 418 }; 419 420 static struct mlxreg_core_item mlxplat_mlxcpld_msn274x_items[] = { 421 { 422 .data = mlxplat_mlxcpld_msn274x_psu_items_data, 423 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 424 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 425 .mask = MLXPLAT_CPLD_PSU_MASK, 426 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_psu_items_data), 427 .inversed = 1, 428 .health = false, 429 }, 430 { 431 .data = mlxplat_mlxcpld_default_ng_pwr_items_data, 432 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 433 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 434 .mask = MLXPLAT_CPLD_PWR_MASK, 435 .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data), 436 .inversed = 0, 437 .health = false, 438 }, 439 { 440 .data = mlxplat_mlxcpld_msn274x_fan_items_data, 441 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 442 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 443 .mask = MLXPLAT_CPLD_FAN_MASK, 444 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_fan_items_data), 445 .inversed = 1, 446 .health = false, 447 }, 448 }; 449 450 static 451 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn274x_data = { 452 .items = mlxplat_mlxcpld_msn274x_items, 453 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_items), 454 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 455 .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 456 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, 457 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, 458 }; 459 460 /* Platform hotplug MSN201x system family data */ 461 static struct mlxreg_core_data mlxplat_mlxcpld_msn201x_pwr_items_data[] = { 462 { 463 .label = "pwr1", 464 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 465 .mask = BIT(0), 466 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 467 }, 468 { 469 .label = "pwr2", 470 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 471 .mask = BIT(1), 472 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 473 }, 474 }; 475 476 static struct mlxreg_core_item mlxplat_mlxcpld_msn201x_items[] = { 477 { 478 .data = mlxplat_mlxcpld_msn201x_pwr_items_data, 479 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, 480 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 481 .mask = MLXPLAT_CPLD_PWR_MASK, 482 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_pwr_items_data), 483 .inversed = 0, 484 .health = false, 485 }, 486 }; 487 488 static 489 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn201x_data = { 490 .items = mlxplat_mlxcpld_msn21xx_items, 491 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_items), 492 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 493 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, 494 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, 495 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, 496 }; 497 498 /* Platform hotplug next generation system family data */ 499 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_psu_items_data[] = { 500 { 501 .label = "psu1", 502 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 503 .mask = BIT(0), 504 .hpdev.brdinfo = &mlxplat_mlxcpld_ng_psu[0], 505 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, 506 }, 507 { 508 .label = "psu2", 509 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 510 .mask = BIT(1), 511 .hpdev.brdinfo = &mlxplat_mlxcpld_ng_psu[1], 512 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, 513 }, 514 }; 515 516 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_fan_items_data[] = { 517 { 518 .label = "fan1", 519 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 520 .mask = BIT(0), 521 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 522 }, 523 { 524 .label = "fan2", 525 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 526 .mask = BIT(1), 527 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 528 }, 529 { 530 .label = "fan3", 531 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 532 .mask = BIT(2), 533 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 534 }, 535 { 536 .label = "fan4", 537 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 538 .mask = BIT(3), 539 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 540 }, 541 { 542 .label = "fan5", 543 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 544 .mask = BIT(4), 545 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 546 }, 547 { 548 .label = "fan6", 549 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 550 .mask = BIT(5), 551 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 552 }, 553 }; 554 555 static struct mlxreg_core_item mlxplat_mlxcpld_default_ng_items[] = { 556 { 557 .data = mlxplat_mlxcpld_default_ng_psu_items_data, 558 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 559 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 560 .mask = MLXPLAT_CPLD_PSU_MASK, 561 .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_psu_items_data), 562 .inversed = 1, 563 .health = false, 564 }, 565 { 566 .data = mlxplat_mlxcpld_default_ng_pwr_items_data, 567 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 568 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 569 .mask = MLXPLAT_CPLD_PWR_MASK, 570 .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data), 571 .inversed = 0, 572 .health = false, 573 }, 574 { 575 .data = mlxplat_mlxcpld_default_ng_fan_items_data, 576 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 577 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 578 .mask = MLXPLAT_CPLD_FAN_NG_MASK, 579 .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data), 580 .inversed = 1, 581 .health = false, 582 }, 583 }; 584 585 static 586 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { 587 .items = mlxplat_mlxcpld_default_ng_items, 588 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_items), 589 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 590 .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 591 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, 592 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, 593 }; 594 595 static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) 596 { 597 switch (reg) { 598 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: 599 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: 600 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: 601 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: 602 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: 603 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: 604 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: 605 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: 606 return true; 607 } 608 return false; 609 } 610 611 static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) 612 { 613 switch (reg) { 614 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: 615 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: 616 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: 617 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: 618 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: 619 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: 620 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: 621 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET: 622 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: 623 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: 624 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: 625 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: 626 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: 627 return true; 628 } 629 return false; 630 } 631 632 static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) 633 { 634 switch (reg) { 635 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: 636 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: 637 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: 638 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: 639 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: 640 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: 641 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: 642 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET: 643 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: 644 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: 645 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: 646 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: 647 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: 648 return true; 649 } 650 return false; 651 } 652 653 struct mlxplat_mlxcpld_regmap_context { 654 void __iomem *base; 655 }; 656 657 static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx; 658 659 static int 660 mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val) 661 { 662 struct mlxplat_mlxcpld_regmap_context *ctx = context; 663 664 *val = ioread8(ctx->base + reg); 665 return 0; 666 } 667 668 static int 669 mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val) 670 { 671 struct mlxplat_mlxcpld_regmap_context *ctx = context; 672 673 iowrite8(val, ctx->base + reg); 674 return 0; 675 } 676 677 static const struct regmap_config mlxplat_mlxcpld_regmap_config = { 678 .reg_bits = 8, 679 .val_bits = 8, 680 .max_register = 255, 681 .cache_type = REGCACHE_FLAT, 682 .writeable_reg = mlxplat_mlxcpld_writeable_reg, 683 .readable_reg = mlxplat_mlxcpld_readable_reg, 684 .volatile_reg = mlxplat_mlxcpld_volatile_reg, 685 .reg_read = mlxplat_mlxcpld_reg_read, 686 .reg_write = mlxplat_mlxcpld_reg_write, 687 }; 688 689 static struct resource mlxplat_mlxcpld_resources[] = { 690 [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"), 691 }; 692 693 static struct platform_device *mlxplat_dev; 694 static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; 695 696 static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) 697 { 698 int i; 699 700 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { 701 mlxplat_mux_data[i].values = mlxplat_default_channels[i]; 702 mlxplat_mux_data[i].n_values = 703 ARRAY_SIZE(mlxplat_default_channels[i]); 704 } 705 mlxplat_hotplug = &mlxplat_mlxcpld_default_data; 706 mlxplat_hotplug->deferred_nr = 707 mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; 708 709 return 1; 710 }; 711 712 static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) 713 { 714 int i; 715 716 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { 717 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; 718 mlxplat_mux_data[i].n_values = 719 ARRAY_SIZE(mlxplat_msn21xx_channels); 720 } 721 mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data; 722 mlxplat_hotplug->deferred_nr = 723 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; 724 725 return 1; 726 }; 727 728 static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) 729 { 730 int i; 731 732 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { 733 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; 734 mlxplat_mux_data[i].n_values = 735 ARRAY_SIZE(mlxplat_msn21xx_channels); 736 } 737 mlxplat_hotplug = &mlxplat_mlxcpld_msn274x_data; 738 mlxplat_hotplug->deferred_nr = 739 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; 740 741 return 1; 742 }; 743 744 static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) 745 { 746 int i; 747 748 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { 749 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; 750 mlxplat_mux_data[i].n_values = 751 ARRAY_SIZE(mlxplat_msn21xx_channels); 752 } 753 mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data; 754 mlxplat_hotplug->deferred_nr = 755 mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; 756 757 return 1; 758 }; 759 760 static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) 761 { 762 int i; 763 764 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { 765 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; 766 mlxplat_mux_data[i].n_values = 767 ARRAY_SIZE(mlxplat_msn21xx_channels); 768 } 769 mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data; 770 mlxplat_hotplug->deferred_nr = 771 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; 772 773 return 1; 774 }; 775 776 static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { 777 { 778 .callback = mlxplat_dmi_msn274x_matched, 779 .matches = { 780 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 781 DMI_MATCH(DMI_PRODUCT_NAME, "MSN274"), 782 }, 783 }, 784 { 785 .callback = mlxplat_dmi_default_matched, 786 .matches = { 787 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 788 DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"), 789 }, 790 }, 791 { 792 .callback = mlxplat_dmi_default_matched, 793 .matches = { 794 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 795 DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"), 796 }, 797 }, 798 { 799 .callback = mlxplat_dmi_default_matched, 800 .matches = { 801 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 802 DMI_MATCH(DMI_PRODUCT_NAME, "MSB"), 803 }, 804 }, 805 { 806 .callback = mlxplat_dmi_default_matched, 807 .matches = { 808 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 809 DMI_MATCH(DMI_PRODUCT_NAME, "MSX"), 810 }, 811 }, 812 { 813 .callback = mlxplat_dmi_msn21xx_matched, 814 .matches = { 815 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 816 DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"), 817 }, 818 }, 819 { 820 .callback = mlxplat_dmi_msn201x_matched, 821 .matches = { 822 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 823 DMI_MATCH(DMI_PRODUCT_NAME, "MSN201"), 824 }, 825 }, 826 { 827 .callback = mlxplat_dmi_qmb7xx_matched, 828 .matches = { 829 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 830 DMI_MATCH(DMI_PRODUCT_NAME, "QMB7"), 831 }, 832 }, 833 { 834 .callback = mlxplat_dmi_qmb7xx_matched, 835 .matches = { 836 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 837 DMI_MATCH(DMI_PRODUCT_NAME, "SN37"), 838 }, 839 }, 840 { 841 .callback = mlxplat_dmi_qmb7xx_matched, 842 .matches = { 843 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 844 DMI_MATCH(DMI_PRODUCT_NAME, "SN34"), 845 }, 846 }, 847 { } 848 }; 849 850 MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table); 851 852 static int mlxplat_mlxcpld_verify_bus_topology(int *nr) 853 { 854 struct i2c_adapter *search_adap; 855 int shift, i; 856 857 /* Scan adapters from expected id to verify it is free. */ 858 *nr = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; 859 for (i = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; i < 860 MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; i++) { 861 search_adap = i2c_get_adapter(i); 862 if (search_adap) { 863 i2c_put_adapter(search_adap); 864 continue; 865 } 866 867 /* Return if expected parent adapter is free. */ 868 if (i == MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR) 869 return 0; 870 break; 871 } 872 873 /* Return with error if free id for adapter is not found. */ 874 if (i == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) 875 return -ENODEV; 876 877 /* Shift adapter ids, since expected parent adapter is not free. */ 878 *nr = i; 879 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { 880 shift = *nr - mlxplat_mux_data[i].parent; 881 mlxplat_mux_data[i].parent = *nr; 882 mlxplat_mux_data[i].base_nr += shift; 883 if (shift > 0) 884 mlxplat_hotplug->shift_nr = shift; 885 } 886 887 return 0; 888 } 889 890 static int __init mlxplat_init(void) 891 { 892 struct mlxplat_priv *priv; 893 int i, nr, err; 894 895 if (!dmi_check_system(mlxplat_dmi_table)) 896 return -ENODEV; 897 898 mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1, 899 mlxplat_lpc_resources, 900 ARRAY_SIZE(mlxplat_lpc_resources)); 901 902 if (IS_ERR(mlxplat_dev)) 903 return PTR_ERR(mlxplat_dev); 904 905 priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv), 906 GFP_KERNEL); 907 if (!priv) { 908 err = -ENOMEM; 909 goto fail_alloc; 910 } 911 platform_set_drvdata(mlxplat_dev, priv); 912 913 err = mlxplat_mlxcpld_verify_bus_topology(&nr); 914 if (nr < 0) 915 goto fail_alloc; 916 917 nr = (nr == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) ? -1 : nr; 918 priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", nr, 919 NULL, 0); 920 if (IS_ERR(priv->pdev_i2c)) { 921 err = PTR_ERR(priv->pdev_i2c); 922 goto fail_alloc; 923 } 924 925 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { 926 priv->pdev_mux[i] = platform_device_register_resndata( 927 &mlxplat_dev->dev, 928 "i2c-mux-reg", i, NULL, 929 0, &mlxplat_mux_data[i], 930 sizeof(mlxplat_mux_data[i])); 931 if (IS_ERR(priv->pdev_mux[i])) { 932 err = PTR_ERR(priv->pdev_mux[i]); 933 goto fail_platform_mux_register; 934 } 935 } 936 937 mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev, 938 mlxplat_lpc_resources[1].start, 1); 939 if (!mlxplat_mlxcpld_regmap_ctx.base) { 940 err = -ENOMEM; 941 goto fail_platform_mux_register; 942 } 943 944 mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL, 945 &mlxplat_mlxcpld_regmap_ctx, 946 &mlxplat_mlxcpld_regmap_config); 947 if (IS_ERR(mlxplat_hotplug->regmap)) { 948 err = PTR_ERR(mlxplat_hotplug->regmap); 949 goto fail_platform_mux_register; 950 } 951 952 priv->pdev_hotplug = platform_device_register_resndata( 953 &mlxplat_dev->dev, "mlxreg-hotplug", 954 PLATFORM_DEVID_NONE, 955 mlxplat_mlxcpld_resources, 956 ARRAY_SIZE(mlxplat_mlxcpld_resources), 957 mlxplat_hotplug, sizeof(*mlxplat_hotplug)); 958 if (IS_ERR(priv->pdev_hotplug)) { 959 err = PTR_ERR(priv->pdev_hotplug); 960 goto fail_platform_mux_register; 961 } 962 963 /* Sync registers with hardware. */ 964 regcache_mark_dirty(mlxplat_hotplug->regmap); 965 err = regcache_sync(mlxplat_hotplug->regmap); 966 if (err) 967 goto fail_platform_hotplug_register; 968 969 return 0; 970 971 fail_platform_hotplug_register: 972 platform_device_unregister(priv->pdev_hotplug); 973 fail_platform_mux_register: 974 while (--i >= 0) 975 platform_device_unregister(priv->pdev_mux[i]); 976 platform_device_unregister(priv->pdev_i2c); 977 fail_alloc: 978 platform_device_unregister(mlxplat_dev); 979 980 return err; 981 } 982 module_init(mlxplat_init); 983 984 static void __exit mlxplat_exit(void) 985 { 986 struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); 987 int i; 988 989 platform_device_unregister(priv->pdev_hotplug); 990 991 for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--) 992 platform_device_unregister(priv->pdev_mux[i]); 993 994 platform_device_unregister(priv->pdev_i2c); 995 platform_device_unregister(mlxplat_dev); 996 } 997 module_exit(mlxplat_exit); 998 999 MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)"); 1000 MODULE_DESCRIPTION("Mellanox platform driver"); 1001 MODULE_LICENSE("Dual BSD/GPL"); 1002