Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.15-rc9 377 lines 12 kB view raw
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/module.h> 39#include <linux/platform_device.h> 40#include <linux/platform_data/i2c-mux-reg.h> 41#include <linux/platform_data/mlxcpld-hotplug.h> 42 43#define MLX_PLAT_DEVICE_NAME "mlxplat" 44 45/* LPC bus IO offsets */ 46#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000 47#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 48#define MLXPLAT_CPLD_LPC_REG_AGGR_ADRR 0x253a 49#define MLXPLAT_CPLD_LPC_REG_PSU_ADRR 0x2558 50#define MLXPLAT_CPLD_LPC_REG_PWR_ADRR 0x2564 51#define MLXPLAT_CPLD_LPC_REG_FAN_ADRR 0x2588 52#define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 53#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb 54#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda 55#define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL 56#define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ 57 MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \ 58 MLXPLAT_CPLD_LPC_PIO_OFFSET) 59#define MLXPLAT_CPLD_LPC_REG2 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ 60 MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \ 61 MLXPLAT_CPLD_LPC_PIO_OFFSET) 62 63/* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */ 64#define MLXPLAT_CPLD_AGGR_PSU_MASK_DEF 0x08 65#define MLXPLAT_CPLD_AGGR_PWR_MASK_DEF 0x08 66#define MLXPLAT_CPLD_AGGR_FAN_MASK_DEF 0x40 67#define MLXPLAT_CPLD_AGGR_MASK_DEF (MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \ 68 MLXPLAT_CPLD_AGGR_FAN_MASK_DEF) 69#define MLXPLAT_CPLD_AGGR_MASK_MSN21XX 0x04 70#define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0) 71#define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0) 72#define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0) 73 74/* Start channel numbers */ 75#define MLXPLAT_CPLD_CH1 2 76#define MLXPLAT_CPLD_CH2 10 77 78/* Number of LPC attached MUX platform devices */ 79#define MLXPLAT_CPLD_LPC_MUX_DEVS 2 80 81/* mlxplat_priv - platform private data 82 * @pdev_i2c - i2c controller platform device 83 * @pdev_mux - array of mux platform devices 84 */ 85struct mlxplat_priv { 86 struct platform_device *pdev_i2c; 87 struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS]; 88 struct platform_device *pdev_hotplug; 89}; 90 91/* Regions for LPC I2C controller and LPC base register space */ 92static const struct resource mlxplat_lpc_resources[] = { 93 [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR, 94 MLXPLAT_CPLD_LPC_IO_RANGE, 95 "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO), 96 [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR, 97 MLXPLAT_CPLD_LPC_IO_RANGE, 98 "mlxplat_cpld_lpc_regs", 99 IORESOURCE_IO), 100}; 101 102/* Platform default channels */ 103static const int mlxplat_default_channels[][8] = { 104 { 105 MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2, 106 MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 + 107 5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7 108 }, 109 { 110 MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2, 111 MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 + 112 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7 113 }, 114}; 115 116/* Platform channels for MSN21xx system family */ 117static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; 118 119/* Platform mux data */ 120static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = { 121 { 122 .parent = 1, 123 .base_nr = MLXPLAT_CPLD_CH1, 124 .write_only = 1, 125 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1, 126 .reg_size = 1, 127 .idle_in_use = 1, 128 }, 129 { 130 .parent = 1, 131 .base_nr = MLXPLAT_CPLD_CH2, 132 .write_only = 1, 133 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2, 134 .reg_size = 1, 135 .idle_in_use = 1, 136 }, 137 138}; 139 140/* Platform hotplug devices */ 141static struct mlxcpld_hotplug_device mlxplat_mlxcpld_psu[] = { 142 { 143 .brdinfo = { I2C_BOARD_INFO("24c02", 0x51) }, 144 .bus = 10, 145 }, 146 { 147 .brdinfo = { I2C_BOARD_INFO("24c02", 0x50) }, 148 .bus = 10, 149 }, 150}; 151 152static struct mlxcpld_hotplug_device mlxplat_mlxcpld_pwr[] = { 153 { 154 .brdinfo = { I2C_BOARD_INFO("dps460", 0x59) }, 155 .bus = 10, 156 }, 157 { 158 .brdinfo = { I2C_BOARD_INFO("dps460", 0x58) }, 159 .bus = 10, 160 }, 161}; 162 163static struct mlxcpld_hotplug_device mlxplat_mlxcpld_fan[] = { 164 { 165 .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, 166 .bus = 11, 167 }, 168 { 169 .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, 170 .bus = 12, 171 }, 172 { 173 .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, 174 .bus = 13, 175 }, 176 { 177 .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, 178 .bus = 14, 179 }, 180}; 181 182/* Platform hotplug default data */ 183static 184struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_default_data = { 185 .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR, 186 .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_DEF, 187 .top_aggr_psu_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF, 188 .psu_reg_offset = MLXPLAT_CPLD_LPC_REG_PSU_ADRR, 189 .psu_mask = MLXPLAT_CPLD_PSU_MASK, 190 .psu_count = ARRAY_SIZE(mlxplat_mlxcpld_psu), 191 .psu = mlxplat_mlxcpld_psu, 192 .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, 193 .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR, 194 .pwr_mask = MLXPLAT_CPLD_PWR_MASK, 195 .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), 196 .pwr = mlxplat_mlxcpld_pwr, 197 .top_aggr_fan_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF, 198 .fan_reg_offset = MLXPLAT_CPLD_LPC_REG_FAN_ADRR, 199 .fan_mask = MLXPLAT_CPLD_FAN_MASK, 200 .fan_count = ARRAY_SIZE(mlxplat_mlxcpld_fan), 201 .fan = mlxplat_mlxcpld_fan, 202}; 203 204/* Platform hotplug MSN21xx system family data */ 205static 206struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { 207 .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR, 208 .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX, 209 .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX, 210 .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR, 211 .pwr_mask = MLXPLAT_CPLD_PWR_MASK, 212 .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), 213}; 214 215static struct resource mlxplat_mlxcpld_resources[] = { 216 [0] = DEFINE_RES_IRQ_NAMED(17, "mlxcpld-hotplug"), 217}; 218 219static struct platform_device *mlxplat_dev; 220static struct mlxcpld_hotplug_platform_data *mlxplat_hotplug; 221 222static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) 223{ 224 int i; 225 226 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { 227 mlxplat_mux_data[i].values = mlxplat_default_channels[i]; 228 mlxplat_mux_data[i].n_values = 229 ARRAY_SIZE(mlxplat_default_channels[i]); 230 } 231 mlxplat_hotplug = &mlxplat_mlxcpld_default_data; 232 233 return 1; 234}; 235 236static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) 237{ 238 int i; 239 240 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { 241 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; 242 mlxplat_mux_data[i].n_values = 243 ARRAY_SIZE(mlxplat_msn21xx_channels); 244 } 245 mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data; 246 247 return 1; 248}; 249 250static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { 251 { 252 .callback = mlxplat_dmi_default_matched, 253 .matches = { 254 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 255 DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"), 256 }, 257 }, 258 { 259 .callback = mlxplat_dmi_default_matched, 260 .matches = { 261 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 262 DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"), 263 }, 264 }, 265 { 266 .callback = mlxplat_dmi_default_matched, 267 .matches = { 268 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 269 DMI_MATCH(DMI_PRODUCT_NAME, "MSB"), 270 }, 271 }, 272 { 273 .callback = mlxplat_dmi_default_matched, 274 .matches = { 275 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 276 DMI_MATCH(DMI_PRODUCT_NAME, "MSX"), 277 }, 278 }, 279 { 280 .callback = mlxplat_dmi_msn21xx_matched, 281 .matches = { 282 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), 283 DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"), 284 }, 285 }, 286 { } 287}; 288 289static int __init mlxplat_init(void) 290{ 291 struct mlxplat_priv *priv; 292 int i, err; 293 294 if (!dmi_check_system(mlxplat_dmi_table)) 295 return -ENODEV; 296 297 mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1, 298 mlxplat_lpc_resources, 299 ARRAY_SIZE(mlxplat_lpc_resources)); 300 301 if (IS_ERR(mlxplat_dev)) 302 return PTR_ERR(mlxplat_dev); 303 304 priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv), 305 GFP_KERNEL); 306 if (!priv) { 307 err = -ENOMEM; 308 goto fail_alloc; 309 } 310 platform_set_drvdata(mlxplat_dev, priv); 311 312 priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1, 313 NULL, 0); 314 if (IS_ERR(priv->pdev_i2c)) { 315 err = PTR_ERR(priv->pdev_i2c); 316 goto fail_alloc; 317 } 318 319 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { 320 priv->pdev_mux[i] = platform_device_register_resndata( 321 &mlxplat_dev->dev, 322 "i2c-mux-reg", i, NULL, 323 0, &mlxplat_mux_data[i], 324 sizeof(mlxplat_mux_data[i])); 325 if (IS_ERR(priv->pdev_mux[i])) { 326 err = PTR_ERR(priv->pdev_mux[i]); 327 goto fail_platform_mux_register; 328 } 329 } 330 331 priv->pdev_hotplug = platform_device_register_resndata( 332 &mlxplat_dev->dev, "mlxcpld-hotplug", 333 PLATFORM_DEVID_NONE, 334 mlxplat_mlxcpld_resources, 335 ARRAY_SIZE(mlxplat_mlxcpld_resources), 336 mlxplat_hotplug, sizeof(*mlxplat_hotplug)); 337 if (IS_ERR(priv->pdev_hotplug)) { 338 err = PTR_ERR(priv->pdev_hotplug); 339 goto fail_platform_mux_register; 340 } 341 342 return 0; 343 344fail_platform_mux_register: 345 while (--i >= 0) 346 platform_device_unregister(priv->pdev_mux[i]); 347 platform_device_unregister(priv->pdev_i2c); 348fail_alloc: 349 platform_device_unregister(mlxplat_dev); 350 351 return err; 352} 353module_init(mlxplat_init); 354 355static void __exit mlxplat_exit(void) 356{ 357 struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); 358 int i; 359 360 platform_device_unregister(priv->pdev_hotplug); 361 362 for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--) 363 platform_device_unregister(priv->pdev_mux[i]); 364 365 platform_device_unregister(priv->pdev_i2c); 366 platform_device_unregister(mlxplat_dev); 367} 368module_exit(mlxplat_exit); 369 370MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)"); 371MODULE_DESCRIPTION("Mellanox platform driver"); 372MODULE_LICENSE("Dual BSD/GPL"); 373MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:"); 374MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:"); 375MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:"); 376MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:"); 377MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:");