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