959 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Nvidia line card driver4 *5 * Copyright (C) 2020 Nvidia Technologies Ltd.6 */7 8#include <linux/device.h>9#include <linux/i2c.h>10#include <linux/module.h>11#include <linux/platform_data/mlxcpld.h>12#include <linux/platform_data/mlxreg.h>13#include <linux/platform_device.h>14#include <linux/regmap.h>15 16/* I2C bus IO offsets */17#define MLXREG_LC_REG_CPLD1_VER_OFFSET 0x250018#define MLXREG_LC_REG_FPGA1_VER_OFFSET 0x250119#define MLXREG_LC_REG_CPLD1_PN_OFFSET 0x250420#define MLXREG_LC_REG_FPGA1_PN_OFFSET 0x250621#define MLXREG_LC_REG_RESET_CAUSE_OFFSET 0x251d22#define MLXREG_LC_REG_LED1_OFFSET 0x252023#define MLXREG_LC_REG_GP0_OFFSET 0x252e24#define MLXREG_LC_REG_FIELD_UPGRADE 0x253425#define MLXREG_LC_CHANNEL_I2C_REG 0x25dc26#define MLXREG_LC_REG_CPLD1_MVER_OFFSET 0x25de27#define MLXREG_LC_REG_FPGA1_MVER_OFFSET 0x25df28#define MLXREG_LC_REG_MAX_POWER_OFFSET 0x25f129#define MLXREG_LC_REG_CONFIG_OFFSET 0x25fb30#define MLXREG_LC_REG_MAX 0x3fff31 32/**33 * enum mlxreg_lc_type - line cards types34 *35 * @MLXREG_LC_SN4800_C16: 100GbE line card with 16 QSFP28 ports;36 */37enum mlxreg_lc_type {38 MLXREG_LC_SN4800_C16 = 0x0000,39};40 41/**42 * enum mlxreg_lc_state - line cards state43 *44 * @MLXREG_LC_INITIALIZED: line card is initialized;45 * @MLXREG_LC_POWERED: line card is powered;46 * @MLXREG_LC_SYNCED: line card is synchronized between hardware and firmware;47 */48enum mlxreg_lc_state {49 MLXREG_LC_INITIALIZED = BIT(0),50 MLXREG_LC_POWERED = BIT(1),51 MLXREG_LC_SYNCED = BIT(2),52};53 54#define MLXREG_LC_CONFIGURED (MLXREG_LC_INITIALIZED | MLXREG_LC_POWERED | MLXREG_LC_SYNCED)55 56/* mlxreg_lc - device private data57 * @dev: platform device;58 * @lock: line card lock;59 * @par_regmap: parent device regmap handle;60 * @data: pltaform core data;61 * @io_data: register access platform data;62 * @led_data: LED platform data ;63 * @mux_data: MUX platform data;64 * @led: LED device;65 * @io_regs: register access device;66 * @mux_brdinfo: mux configuration;67 * @mux: mux devices;68 * @aux_devs: I2C devices feeding by auxiliary power;69 * @aux_devs_num: number of I2C devices feeding by auxiliary power;70 * @main_devs: I2C devices feeding by main power;71 * @main_devs_num: number of I2C devices feeding by main power;72 * @state: line card state;73 */74struct mlxreg_lc {75 struct device *dev;76 struct mutex lock; /* line card access lock */77 void *par_regmap;78 struct mlxreg_core_data *data;79 struct mlxreg_core_platform_data *io_data;80 struct mlxreg_core_platform_data *led_data;81 struct mlxcpld_mux_plat_data *mux_data;82 struct platform_device *led;83 struct platform_device *io_regs;84 struct i2c_board_info *mux_brdinfo;85 struct platform_device *mux;86 struct mlxreg_hotplug_device *aux_devs;87 int aux_devs_num;88 struct mlxreg_hotplug_device *main_devs;89 int main_devs_num;90 enum mlxreg_lc_state state;91};92 93static bool mlxreg_lc_writeable_reg(struct device *dev, unsigned int reg)94{95 switch (reg) {96 case MLXREG_LC_REG_LED1_OFFSET:97 case MLXREG_LC_REG_GP0_OFFSET:98 case MLXREG_LC_REG_FIELD_UPGRADE:99 case MLXREG_LC_CHANNEL_I2C_REG:100 return true;101 }102 return false;103}104 105static bool mlxreg_lc_readable_reg(struct device *dev, unsigned int reg)106{107 switch (reg) {108 case MLXREG_LC_REG_CPLD1_VER_OFFSET:109 case MLXREG_LC_REG_FPGA1_VER_OFFSET:110 case MLXREG_LC_REG_CPLD1_PN_OFFSET:111 case MLXREG_LC_REG_FPGA1_PN_OFFSET:112 case MLXREG_LC_REG_RESET_CAUSE_OFFSET:113 case MLXREG_LC_REG_LED1_OFFSET:114 case MLXREG_LC_REG_GP0_OFFSET:115 case MLXREG_LC_REG_FIELD_UPGRADE:116 case MLXREG_LC_CHANNEL_I2C_REG:117 case MLXREG_LC_REG_CPLD1_MVER_OFFSET:118 case MLXREG_LC_REG_FPGA1_MVER_OFFSET:119 case MLXREG_LC_REG_MAX_POWER_OFFSET:120 case MLXREG_LC_REG_CONFIG_OFFSET:121 return true;122 }123 return false;124}125 126static bool mlxreg_lc_volatile_reg(struct device *dev, unsigned int reg)127{128 switch (reg) {129 case MLXREG_LC_REG_CPLD1_VER_OFFSET:130 case MLXREG_LC_REG_FPGA1_VER_OFFSET:131 case MLXREG_LC_REG_CPLD1_PN_OFFSET:132 case MLXREG_LC_REG_FPGA1_PN_OFFSET:133 case MLXREG_LC_REG_RESET_CAUSE_OFFSET:134 case MLXREG_LC_REG_LED1_OFFSET:135 case MLXREG_LC_REG_GP0_OFFSET:136 case MLXREG_LC_REG_FIELD_UPGRADE:137 case MLXREG_LC_CHANNEL_I2C_REG:138 case MLXREG_LC_REG_CPLD1_MVER_OFFSET:139 case MLXREG_LC_REG_FPGA1_MVER_OFFSET:140 case MLXREG_LC_REG_MAX_POWER_OFFSET:141 case MLXREG_LC_REG_CONFIG_OFFSET:142 return true;143 }144 return false;145}146 147static const struct reg_default mlxreg_lc_regmap_default[] = {148 { MLXREG_LC_CHANNEL_I2C_REG, 0x00 },149};150 151/* Configuration for the register map of a device with 2 bytes address space. */152static const struct regmap_config mlxreg_lc_regmap_conf = {153 .reg_bits = 16,154 .val_bits = 8,155 .max_register = MLXREG_LC_REG_MAX,156 .cache_type = REGCACHE_FLAT,157 .writeable_reg = mlxreg_lc_writeable_reg,158 .readable_reg = mlxreg_lc_readable_reg,159 .volatile_reg = mlxreg_lc_volatile_reg,160 .reg_defaults = mlxreg_lc_regmap_default,161 .num_reg_defaults = ARRAY_SIZE(mlxreg_lc_regmap_default),162};163 164/* Default channels vector.165 * It contains only the channels, which physically connected to the devices,166 * empty channels are skipped.167 */168static int mlxreg_lc_chan[] = {169 0x04, 0x05, 0x06, 0x07, 0x08, 0x10, 0x20, 0x21, 0x22, 0x23, 0x40, 0x41,170 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,171 0x4e, 0x4f172};173 174/* Defaul mux configuration. */175static struct mlxcpld_mux_plat_data mlxreg_lc_mux_data[] = {176 {177 .chan_ids = mlxreg_lc_chan,178 .num_adaps = ARRAY_SIZE(mlxreg_lc_chan),179 .sel_reg_addr = MLXREG_LC_CHANNEL_I2C_REG,180 .reg_size = 2,181 },182};183 184/* Defaul mux board info. */185static struct i2c_board_info mlxreg_lc_mux_brdinfo = {186 I2C_BOARD_INFO("i2c-mux-mlxcpld", 0x32),187};188 189/* Line card default auxiliary power static devices. */190static struct i2c_board_info mlxreg_lc_aux_pwr_devices[] = {191 {192 I2C_BOARD_INFO("24c32", 0x51),193 },194 {195 I2C_BOARD_INFO("24c32", 0x51),196 },197};198 199/* Line card default auxiliary power board info. */200static struct mlxreg_hotplug_device mlxreg_lc_aux_pwr_brdinfo[] = {201 {202 .brdinfo = &mlxreg_lc_aux_pwr_devices[0],203 .nr = 3,204 },205 {206 .brdinfo = &mlxreg_lc_aux_pwr_devices[1],207 .nr = 4,208 },209};210 211/* Line card default main power static devices. */212static struct i2c_board_info mlxreg_lc_main_pwr_devices[] = {213 {214 I2C_BOARD_INFO("mp2975", 0x62),215 },216 {217 I2C_BOARD_INFO("mp2975", 0x64),218 },219 {220 I2C_BOARD_INFO("max11603", 0x6d),221 },222 {223 I2C_BOARD_INFO("lm25066", 0x15),224 },225};226 227/* Line card default main power board info. */228static struct mlxreg_hotplug_device mlxreg_lc_main_pwr_brdinfo[] = {229 {230 .brdinfo = &mlxreg_lc_main_pwr_devices[0],231 .nr = 0,232 },233 {234 .brdinfo = &mlxreg_lc_main_pwr_devices[1],235 .nr = 0,236 },237 {238 .brdinfo = &mlxreg_lc_main_pwr_devices[2],239 .nr = 1,240 },241 {242 .brdinfo = &mlxreg_lc_main_pwr_devices[3],243 .nr = 2,244 },245};246 247/* LED default data. */248static struct mlxreg_core_data mlxreg_lc_led_data[] = {249 {250 .label = "status:green",251 .reg = MLXREG_LC_REG_LED1_OFFSET,252 .mask = GENMASK(7, 4),253 },254 {255 .label = "status:orange",256 .reg = MLXREG_LC_REG_LED1_OFFSET,257 .mask = GENMASK(7, 4),258 },259};260 261static struct mlxreg_core_platform_data mlxreg_lc_led = {262 .identity = "pci",263 .data = mlxreg_lc_led_data,264 .counter = ARRAY_SIZE(mlxreg_lc_led_data),265};266 267/* Default register access data. */268static struct mlxreg_core_data mlxreg_lc_io_data[] = {269 {270 .label = "cpld1_version",271 .reg = MLXREG_LC_REG_CPLD1_VER_OFFSET,272 .bit = GENMASK(7, 0),273 .mode = 0444,274 },275 {276 .label = "fpga1_version",277 .reg = MLXREG_LC_REG_FPGA1_VER_OFFSET,278 .bit = GENMASK(7, 0),279 .mode = 0444,280 },281 {282 .label = "cpld1_pn",283 .reg = MLXREG_LC_REG_CPLD1_PN_OFFSET,284 .bit = GENMASK(15, 0),285 .mode = 0444,286 .regnum = 2,287 },288 {289 .label = "fpga1_pn",290 .reg = MLXREG_LC_REG_FPGA1_PN_OFFSET,291 .bit = GENMASK(15, 0),292 .mode = 0444,293 .regnum = 2,294 },295 {296 .label = "cpld1_version_min",297 .reg = MLXREG_LC_REG_CPLD1_MVER_OFFSET,298 .bit = GENMASK(7, 0),299 .mode = 0444,300 },301 {302 .label = "fpga1_version_min",303 .reg = MLXREG_LC_REG_FPGA1_MVER_OFFSET,304 .bit = GENMASK(7, 0),305 .mode = 0444,306 },307 {308 .label = "reset_fpga_not_done",309 .reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET,310 .mask = GENMASK(7, 0) & ~BIT(1),311 .mode = 0444,312 },313 {314 .label = "reset_aux_pwr_or_ref",315 .reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET,316 .mask = GENMASK(7, 0) & ~BIT(2),317 .mode = 0444,318 },319 {320 .label = "reset_dc_dc_pwr_fail",321 .reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET,322 .mask = GENMASK(7, 0) & ~BIT(3),323 .mode = 0444,324 },325 {326 .label = "reset_from_chassis",327 .reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET,328 .mask = GENMASK(7, 0) & ~BIT(4),329 .mode = 0444,330 },331 {332 .label = "reset_pwr_off_from_chassis",333 .reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET,334 .mask = GENMASK(7, 0) & ~BIT(5),335 .mode = 0444,336 },337 {338 .label = "reset_line_card",339 .reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET,340 .mask = GENMASK(7, 0) & ~BIT(6),341 .mode = 0444,342 },343 {344 .label = "reset_line_card_pwr_en",345 .reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET,346 .mask = GENMASK(7, 0) & ~BIT(7),347 .mode = 0444,348 },349 {350 .label = "cpld_upgrade_en",351 .reg = MLXREG_LC_REG_FIELD_UPGRADE,352 .mask = GENMASK(7, 0) & ~BIT(0),353 .mode = 0644,354 .secured = 1,355 },356 {357 .label = "fpga_upgrade_en",358 .reg = MLXREG_LC_REG_FIELD_UPGRADE,359 .mask = GENMASK(7, 0) & ~BIT(1),360 .mode = 0644,361 .secured = 1,362 },363 {364 .label = "qsfp_pwr_en",365 .reg = MLXREG_LC_REG_GP0_OFFSET,366 .mask = GENMASK(7, 0) & ~BIT(0),367 .mode = 0644,368 },369 {370 .label = "vpd_wp",371 .reg = MLXREG_LC_REG_GP0_OFFSET,372 .mask = GENMASK(7, 0) & ~BIT(3),373 .mode = 0644,374 .secured = 1,375 },376 {377 .label = "agb_spi_burn_en",378 .reg = MLXREG_LC_REG_GP0_OFFSET,379 .mask = GENMASK(7, 0) & ~BIT(5),380 .mode = 0644,381 .secured = 1,382 },383 {384 .label = "fpga_spi_burn_en",385 .reg = MLXREG_LC_REG_GP0_OFFSET,386 .mask = GENMASK(7, 0) & ~BIT(6),387 .mode = 0644,388 .secured = 1,389 },390 {391 .label = "max_power",392 .reg = MLXREG_LC_REG_MAX_POWER_OFFSET,393 .bit = GENMASK(15, 0),394 .mode = 0444,395 .regnum = 2,396 },397 {398 .label = "config",399 .reg = MLXREG_LC_REG_CONFIG_OFFSET,400 .bit = GENMASK(15, 0),401 .mode = 0444,402 .regnum = 2,403 },404};405 406static struct mlxreg_core_platform_data mlxreg_lc_regs_io = {407 .data = mlxreg_lc_io_data,408 .counter = ARRAY_SIZE(mlxreg_lc_io_data),409};410 411static int412mlxreg_lc_create_static_devices(struct mlxreg_lc *mlxreg_lc, struct mlxreg_hotplug_device *devs,413 int size)414{415 struct mlxreg_hotplug_device *dev = devs;416 int i, ret;417 418 /* Create static I2C device feeding by auxiliary or main power. */419 for (i = 0; i < size; i++, dev++) {420 dev->client = i2c_new_client_device(dev->adapter, dev->brdinfo);421 if (IS_ERR(dev->client)) {422 dev_err(mlxreg_lc->dev, "Failed to create client %s at bus %d at addr 0x%02x\n",423 dev->brdinfo->type, dev->nr, dev->brdinfo->addr);424 425 dev->adapter = NULL;426 ret = PTR_ERR(dev->client);427 goto fail_create_static_devices;428 }429 }430 431 return 0;432 433fail_create_static_devices:434 while (--i >= 0) {435 dev = devs + i;436 i2c_unregister_device(dev->client);437 dev->client = NULL;438 }439 return ret;440}441 442static void443mlxreg_lc_destroy_static_devices(struct mlxreg_lc *mlxreg_lc, struct mlxreg_hotplug_device *devs,444 int size)445{446 struct mlxreg_hotplug_device *dev = devs;447 int i;448 449 /* Destroy static I2C device feeding by auxiliary or main power. */450 for (i = 0; i < size; i++, dev++) {451 if (dev->client) {452 i2c_unregister_device(dev->client);453 dev->client = NULL;454 }455 }456}457 458static int mlxreg_lc_power_on_off(struct mlxreg_lc *mlxreg_lc, u8 action)459{460 u32 regval;461 int err;462 463 err = regmap_read(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_pwr, ®val);464 if (err)465 goto regmap_read_fail;466 467 if (action)468 regval |= BIT(mlxreg_lc->data->slot - 1);469 else470 regval &= ~BIT(mlxreg_lc->data->slot - 1);471 472 err = regmap_write(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_pwr, regval);473 474regmap_read_fail:475 return err;476}477 478static int mlxreg_lc_enable_disable(struct mlxreg_lc *mlxreg_lc, bool action)479{480 u32 regval;481 int err;482 483 /*484 * Hardware holds the line card after powering on in the disabled state. Holding line card485 * in disabled state protects access to the line components, like FPGA and gearboxes.486 * Line card should be enabled in order to get it in operational state. Line card could be487 * disabled for moving it to non-operational state. Enabling line card does not affect the488 * line card which is already has been enabled. Disabling does not affect the disabled line489 * card.490 */491 err = regmap_read(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_ena, ®val);492 if (err)493 goto regmap_read_fail;494 495 if (action)496 regval |= BIT(mlxreg_lc->data->slot - 1);497 else498 regval &= ~BIT(mlxreg_lc->data->slot - 1);499 500 err = regmap_write(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_ena, regval);501 502regmap_read_fail:503 return err;504}505 506static int507mlxreg_lc_sn4800_c16_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap,508 struct mlxreg_core_data *data)509{510 struct device *dev = &data->hpdev.client->dev;511 512 /* Set line card configuration according to the type. */513 mlxreg_lc->mux_data = mlxreg_lc_mux_data;514 mlxreg_lc->io_data = &mlxreg_lc_regs_io;515 mlxreg_lc->led_data = &mlxreg_lc_led;516 mlxreg_lc->mux_brdinfo = &mlxreg_lc_mux_brdinfo;517 518 mlxreg_lc->aux_devs = devm_kmemdup(dev, mlxreg_lc_aux_pwr_brdinfo,519 sizeof(mlxreg_lc_aux_pwr_brdinfo), GFP_KERNEL);520 if (!mlxreg_lc->aux_devs)521 return -ENOMEM;522 mlxreg_lc->aux_devs_num = ARRAY_SIZE(mlxreg_lc_aux_pwr_brdinfo);523 mlxreg_lc->main_devs = devm_kmemdup(dev, mlxreg_lc_main_pwr_brdinfo,524 sizeof(mlxreg_lc_main_pwr_brdinfo), GFP_KERNEL);525 if (!mlxreg_lc->main_devs)526 return -ENOMEM;527 mlxreg_lc->main_devs_num = ARRAY_SIZE(mlxreg_lc_main_pwr_brdinfo);528 529 return 0;530}531 532static void533mlxreg_lc_state_update(struct mlxreg_lc *mlxreg_lc, enum mlxreg_lc_state state, u8 action)534{535 if (action)536 mlxreg_lc->state |= state;537 else538 mlxreg_lc->state &= ~state;539}540 541static void542mlxreg_lc_state_update_locked(struct mlxreg_lc *mlxreg_lc, enum mlxreg_lc_state state, u8 action)543{544 mutex_lock(&mlxreg_lc->lock);545 546 if (action)547 mlxreg_lc->state |= state;548 else549 mlxreg_lc->state &= ~state;550 551 mutex_unlock(&mlxreg_lc->lock);552}553 554/*555 * Callback is to be called from mlxreg-hotplug driver to notify about line card about received556 * event.557 */558static int mlxreg_lc_event_handler(void *handle, enum mlxreg_hotplug_kind kind, u8 action)559{560 struct mlxreg_lc *mlxreg_lc = handle;561 int err = 0;562 563 dev_info(mlxreg_lc->dev, "linecard#%d state %d event kind %d action %d\n",564 mlxreg_lc->data->slot, mlxreg_lc->state, kind, action);565 566 mutex_lock(&mlxreg_lc->lock);567 if (!(mlxreg_lc->state & MLXREG_LC_INITIALIZED))568 goto mlxreg_lc_non_initialzed_exit;569 570 switch (kind) {571 case MLXREG_HOTPLUG_LC_SYNCED:572 /*573 * Synchronization event - hardware and firmware are synchronized. Power on/off574 * line card - to allow/disallow main power source.575 */576 mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_SYNCED, action);577 /* Power line card if it is not powered yet. */578 if (!(mlxreg_lc->state & MLXREG_LC_POWERED) && action) {579 err = mlxreg_lc_power_on_off(mlxreg_lc, 1);580 if (err)581 goto mlxreg_lc_power_on_off_fail;582 }583 /* In case line card is configured - enable it. */584 if (mlxreg_lc->state & MLXREG_LC_CONFIGURED && action)585 err = mlxreg_lc_enable_disable(mlxreg_lc, 1);586 break;587 case MLXREG_HOTPLUG_LC_POWERED:588 /* Power event - attach or de-attach line card device feeding by the main power. */589 if (action) {590 /* Do not create devices, if line card is already powered. */591 if (mlxreg_lc->state & MLXREG_LC_POWERED) {592 /* In case line card is configured - enable it. */593 if (mlxreg_lc->state & MLXREG_LC_CONFIGURED)594 err = mlxreg_lc_enable_disable(mlxreg_lc, 1);595 596 goto mlxreg_lc_enable_disable_exit;597 }598 err = mlxreg_lc_create_static_devices(mlxreg_lc, mlxreg_lc->main_devs,599 mlxreg_lc->main_devs_num);600 if (err)601 goto mlxreg_lc_create_static_devices_fail;602 603 /* In case line card is already in ready state - enable it. */604 if (mlxreg_lc->state & MLXREG_LC_CONFIGURED)605 err = mlxreg_lc_enable_disable(mlxreg_lc, 1);606 } else {607 mlxreg_lc_destroy_static_devices(mlxreg_lc, mlxreg_lc->main_devs,608 mlxreg_lc->main_devs_num);609 }610 mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_POWERED, action);611 break;612 case MLXREG_HOTPLUG_LC_READY:613 /*614 * Ready event – enable line card by releasing it from reset or disable it by put615 * to reset state.616 */617 err = mlxreg_lc_enable_disable(mlxreg_lc, !!action);618 break;619 case MLXREG_HOTPLUG_LC_THERMAL:620 /* Thermal shutdown event – power off line card. */621 if (action)622 err = mlxreg_lc_power_on_off(mlxreg_lc, 0);623 break;624 default:625 break;626 }627 628mlxreg_lc_enable_disable_exit:629mlxreg_lc_power_on_off_fail:630mlxreg_lc_create_static_devices_fail:631mlxreg_lc_non_initialzed_exit:632 mutex_unlock(&mlxreg_lc->lock);633 634 return err;635}636 637/*638 * Callback is to be called from i2c-mux-mlxcpld driver to indicate that all adapter devices has639 * been created.640 */641static int mlxreg_lc_completion_notify(void *handle, struct i2c_adapter *parent,642 struct i2c_adapter *adapters[])643{644 struct mlxreg_hotplug_device *main_dev, *aux_dev;645 struct mlxreg_lc *mlxreg_lc = handle;646 u32 regval;647 int i, err;648 649 /* Update I2C devices feeding by auxiliary power. */650 aux_dev = mlxreg_lc->aux_devs;651 for (i = 0; i < mlxreg_lc->aux_devs_num; i++, aux_dev++) {652 aux_dev->adapter = adapters[aux_dev->nr];653 aux_dev->nr = adapters[aux_dev->nr]->nr;654 }655 656 err = mlxreg_lc_create_static_devices(mlxreg_lc, mlxreg_lc->aux_devs,657 mlxreg_lc->aux_devs_num);658 if (err)659 return err;660 661 /* Update I2C devices feeding by main power. */662 main_dev = mlxreg_lc->main_devs;663 for (i = 0; i < mlxreg_lc->main_devs_num; i++, main_dev++) {664 main_dev->adapter = adapters[main_dev->nr];665 main_dev->nr = adapters[main_dev->nr]->nr;666 }667 668 /* Verify if line card is powered. */669 err = regmap_read(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_pwr, ®val);670 if (err)671 goto mlxreg_lc_regmap_read_power_fail;672 673 if (regval & mlxreg_lc->data->mask) {674 err = mlxreg_lc_create_static_devices(mlxreg_lc, mlxreg_lc->main_devs,675 mlxreg_lc->main_devs_num);676 if (err)677 goto mlxreg_lc_create_static_devices_failed;678 679 mlxreg_lc_state_update_locked(mlxreg_lc, MLXREG_LC_POWERED, 1);680 }681 682 /* Verify if line card is synchronized. */683 err = regmap_read(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_sync, ®val);684 if (err)685 goto mlxreg_lc_regmap_read_sync_fail;686 687 /* Power on line card if necessary. */688 if (regval & mlxreg_lc->data->mask) {689 mlxreg_lc->state |= MLXREG_LC_SYNCED;690 mlxreg_lc_state_update_locked(mlxreg_lc, MLXREG_LC_SYNCED, 1);691 if (mlxreg_lc->state & ~MLXREG_LC_POWERED) {692 err = mlxreg_lc_power_on_off(mlxreg_lc, 1);693 if (err)694 goto mlxreg_lc_regmap_power_on_off_fail;695 }696 }697 698 mlxreg_lc_state_update_locked(mlxreg_lc, MLXREG_LC_INITIALIZED, 1);699 700 return 0;701 702mlxreg_lc_regmap_power_on_off_fail:703mlxreg_lc_regmap_read_sync_fail:704 if (mlxreg_lc->state & MLXREG_LC_POWERED)705 mlxreg_lc_destroy_static_devices(mlxreg_lc, mlxreg_lc->main_devs,706 mlxreg_lc->main_devs_num);707mlxreg_lc_create_static_devices_failed:708 mlxreg_lc_destroy_static_devices(mlxreg_lc, mlxreg_lc->aux_devs, mlxreg_lc->aux_devs_num);709mlxreg_lc_regmap_read_power_fail:710 return err;711}712 713static int714mlxreg_lc_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap,715 struct mlxreg_core_data *data)716{717 struct device *dev = &data->hpdev.client->dev;718 int lsb, err;719 u32 regval;720 721 /* Validate line card type. */722 err = regmap_read(regmap, MLXREG_LC_REG_CONFIG_OFFSET, &lsb);723 err = (!err) ? regmap_read(regmap, MLXREG_LC_REG_CONFIG_OFFSET, ®val) : err;724 if (err)725 return err;726 regval = (regval & GENMASK(7, 0)) << 8 | (lsb & GENMASK(7, 0));727 switch (regval) {728 case MLXREG_LC_SN4800_C16:729 err = mlxreg_lc_sn4800_c16_config_init(mlxreg_lc, regmap, data);730 if (err) {731 dev_err(dev, "Failed to config client %s at bus %d at addr 0x%02x\n",732 data->hpdev.brdinfo->type, data->hpdev.nr,733 data->hpdev.brdinfo->addr);734 return err;735 }736 break;737 default:738 return -ENODEV;739 }740 741 /* Create mux infrastructure. */742 mlxreg_lc->mux_data->handle = mlxreg_lc;743 mlxreg_lc->mux_data->completion_notify = mlxreg_lc_completion_notify;744 mlxreg_lc->mux_brdinfo->platform_data = mlxreg_lc->mux_data;745 mlxreg_lc->mux = platform_device_register_resndata(dev, "i2c-mux-mlxcpld", data->hpdev.nr,746 NULL, 0, mlxreg_lc->mux_data,747 sizeof(*mlxreg_lc->mux_data));748 if (IS_ERR(mlxreg_lc->mux)) {749 dev_err(dev, "Failed to create mux infra for client %s at bus %d at addr 0x%02x\n",750 data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr);751 return PTR_ERR(mlxreg_lc->mux);752 }753 754 /* Register IO access driver. */755 if (mlxreg_lc->io_data) {756 mlxreg_lc->io_data->regmap = regmap;757 mlxreg_lc->io_regs =758 platform_device_register_resndata(dev, "mlxreg-io", data->hpdev.nr, NULL, 0,759 mlxreg_lc->io_data, sizeof(*mlxreg_lc->io_data));760 if (IS_ERR(mlxreg_lc->io_regs)) {761 dev_err(dev, "Failed to create regio for client %s at bus %d at addr 0x%02x\n",762 data->hpdev.brdinfo->type, data->hpdev.nr,763 data->hpdev.brdinfo->addr);764 err = PTR_ERR(mlxreg_lc->io_regs);765 goto fail_register_io;766 }767 }768 769 /* Register LED driver. */770 if (mlxreg_lc->led_data) {771 mlxreg_lc->led_data->regmap = regmap;772 mlxreg_lc->led =773 platform_device_register_resndata(dev, "leds-mlxreg", data->hpdev.nr, NULL, 0,774 mlxreg_lc->led_data,775 sizeof(*mlxreg_lc->led_data));776 if (IS_ERR(mlxreg_lc->led)) {777 dev_err(dev, "Failed to create LED objects for client %s at bus %d at addr 0x%02x\n",778 data->hpdev.brdinfo->type, data->hpdev.nr,779 data->hpdev.brdinfo->addr);780 err = PTR_ERR(mlxreg_lc->led);781 goto fail_register_led;782 }783 }784 785 return 0;786 787fail_register_led:788 if (mlxreg_lc->io_regs)789 platform_device_unregister(mlxreg_lc->io_regs);790fail_register_io:791 if (mlxreg_lc->mux)792 platform_device_unregister(mlxreg_lc->mux);793 794 return err;795}796 797static void mlxreg_lc_config_exit(struct mlxreg_lc *mlxreg_lc)798{799 /* Unregister LED driver. */800 if (mlxreg_lc->led)801 platform_device_unregister(mlxreg_lc->led);802 /* Unregister IO access driver. */803 if (mlxreg_lc->io_regs)804 platform_device_unregister(mlxreg_lc->io_regs);805 /* Remove mux infrastructure. */806 if (mlxreg_lc->mux)807 platform_device_unregister(mlxreg_lc->mux);808}809 810static int mlxreg_lc_probe(struct platform_device *pdev)811{812 struct mlxreg_core_hotplug_platform_data *par_pdata;813 struct mlxreg_core_data *data;814 struct mlxreg_lc *mlxreg_lc;815 void *regmap;816 int i, err;817 818 data = dev_get_platdata(&pdev->dev);819 if (!data)820 return -EINVAL;821 822 mlxreg_lc = devm_kzalloc(&pdev->dev, sizeof(*mlxreg_lc), GFP_KERNEL);823 if (!mlxreg_lc)824 return -ENOMEM;825 826 mutex_init(&mlxreg_lc->lock);827 /* Set event notification callback. */828 data->notifier->user_handler = mlxreg_lc_event_handler;829 data->notifier->handle = mlxreg_lc;830 831 data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr);832 if (!data->hpdev.adapter) {833 dev_err(&pdev->dev, "Failed to get adapter for bus %d\n",834 data->hpdev.nr);835 err = -EFAULT;836 goto i2c_get_adapter_fail;837 }838 839 /* Create device at the top of line card I2C tree.*/840 data->hpdev.client = i2c_new_client_device(data->hpdev.adapter,841 data->hpdev.brdinfo);842 if (IS_ERR(data->hpdev.client)) {843 dev_err(&pdev->dev, "Failed to create client %s at bus %d at addr 0x%02x\n",844 data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr);845 err = PTR_ERR(data->hpdev.client);846 goto i2c_new_device_fail;847 }848 849 regmap = devm_regmap_init_i2c(data->hpdev.client,850 &mlxreg_lc_regmap_conf);851 if (IS_ERR(regmap)) {852 dev_err(&pdev->dev, "Failed to create regmap for client %s at bus %d at addr 0x%02x\n",853 data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr);854 err = PTR_ERR(regmap);855 goto devm_regmap_init_i2c_fail;856 }857 858 /* Set default registers. */859 for (i = 0; i < mlxreg_lc_regmap_conf.num_reg_defaults; i++) {860 err = regmap_write(regmap, mlxreg_lc_regmap_default[i].reg,861 mlxreg_lc_regmap_default[i].def);862 if (err) {863 dev_err(&pdev->dev, "Failed to set default regmap %d for client %s at bus %d at addr 0x%02x\n",864 i, data->hpdev.brdinfo->type, data->hpdev.nr,865 data->hpdev.brdinfo->addr);866 goto regmap_write_fail;867 }868 }869 870 /* Sync registers with hardware. */871 regcache_mark_dirty(regmap);872 err = regcache_sync(regmap);873 if (err) {874 dev_err(&pdev->dev, "Failed to sync regmap for client %s at bus %d at addr 0x%02x\n",875 data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr);876 goto regcache_sync_fail;877 }878 879 par_pdata = data->hpdev.brdinfo->platform_data;880 mlxreg_lc->par_regmap = par_pdata->regmap;881 mlxreg_lc->data = data;882 mlxreg_lc->dev = &pdev->dev;883 platform_set_drvdata(pdev, mlxreg_lc);884 885 /* Configure line card. */886 err = mlxreg_lc_config_init(mlxreg_lc, regmap, data);887 if (err)888 goto mlxreg_lc_config_init_fail;889 890 return 0;891 892mlxreg_lc_config_init_fail:893regcache_sync_fail:894regmap_write_fail:895devm_regmap_init_i2c_fail:896 i2c_unregister_device(data->hpdev.client);897 data->hpdev.client = NULL;898i2c_new_device_fail:899 i2c_put_adapter(data->hpdev.adapter);900 data->hpdev.adapter = NULL;901i2c_get_adapter_fail:902 /* Clear event notification callback and handle. */903 if (data->notifier) {904 data->notifier->user_handler = NULL;905 data->notifier->handle = NULL;906 }907 return err;908}909 910static void mlxreg_lc_remove(struct platform_device *pdev)911{912 struct mlxreg_core_data *data = dev_get_platdata(&pdev->dev);913 struct mlxreg_lc *mlxreg_lc = platform_get_drvdata(pdev);914 915 mlxreg_lc_state_update_locked(mlxreg_lc, MLXREG_LC_INITIALIZED, 0);916 917 /*918 * Probing and removing are invoked by hotplug events raised upon line card insertion and919 * removing. If probing procedure fails all data is cleared. However, hotplug event still920 * will be raised on line card removing and activate removing procedure. In this case there921 * is nothing to remove.922 */923 if (!data->notifier || !data->notifier->handle)924 return;925 926 /* Clear event notification callback and handle. */927 data->notifier->user_handler = NULL;928 data->notifier->handle = NULL;929 930 /* Destroy static I2C device feeding by main power. */931 mlxreg_lc_destroy_static_devices(mlxreg_lc, mlxreg_lc->main_devs,932 mlxreg_lc->main_devs_num);933 /* Destroy static I2C device feeding by auxiliary power. */934 mlxreg_lc_destroy_static_devices(mlxreg_lc, mlxreg_lc->aux_devs, mlxreg_lc->aux_devs_num);935 /* Unregister underlying drivers. */936 mlxreg_lc_config_exit(mlxreg_lc);937 if (data->hpdev.client) {938 i2c_unregister_device(data->hpdev.client);939 data->hpdev.client = NULL;940 i2c_put_adapter(data->hpdev.adapter);941 data->hpdev.adapter = NULL;942 }943}944 945static struct platform_driver mlxreg_lc_driver = {946 .probe = mlxreg_lc_probe,947 .remove_new = mlxreg_lc_remove,948 .driver = {949 .name = "mlxreg-lc",950 },951};952 953module_platform_driver(mlxreg_lc_driver);954 955MODULE_AUTHOR("Vadim Pasternak <vadimp@nvidia.com>");956MODULE_DESCRIPTION("Nvidia line card platform driver");957MODULE_LICENSE("Dual BSD/GPL");958MODULE_ALIAS("platform:mlxreg-lc");959