RE: [PATCH platform-next 07/10] platform/mellanox: mlxreg-lc: Add initial support for Nvidia line card devices

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




> -----Original Message-----
> From: Hans de Goede <hdegoede@xxxxxxxxxx>
> Sent: Tuesday, October 19, 2021 11:47 AM
> To: Vadim Pasternak <vadimp@xxxxxxxxxx>
> Cc: platform-driver-x86@xxxxxxxxxxxxxxx; Michael Shych
> <michaelsh@xxxxxxxxxx>
> Subject: Re: [PATCH platform-next 07/10] platform/mellanox: mlxreg-lc: Add
> initial support for Nvidia line card devices
> 
> Hi again,
> 
> On 10/19/21 10:45, Hans de Goede wrote:
> > Hi,
> >
> > The headers of this email contain:
> >
> > Content-Type: text/plain; charset="y"
> >
> > With "y" not being any known / valid character encoding.
> 
> I wonder if git send-email asked you to specify an encoding and instead of
> hitting enter to get the default you input 'y' because you thought it was
> asking for confirmation for something... ?

Hi Hans,

Sorry for this issue.
To be honest I don't remember, but maybe I really put 'y' by mistake.
I should be more careful next time.

Thanks,
Vadim.

> 
> Regards,
> 
> Hans
> 
> 
> >
> > I've fixed this up by editing the raw email before git am-ing it,
> > dropping the '; charset="y"' part.
> >
> > If you can figure out what happened here and avoid this next time that
> > would be good.
> >
> > If you cannot figure it out, will just leave it as some mysterious
> > glitch.
> >
> > Regards,
> >
> > Hans
> >
> >
> >
> >
> > On 10/2/21 11:32, Vadim Pasternak wrote:
> >> Provide support for the Nvidia MSN4800-XX line cards for MSN4800
> >> Ethernet modular switch system, providing a high performance
> >> switching solution for Enterprise Data Centers (EDC) for building
> >> Ethernet based clusters, High-Performance Computing (HPC) and
> embedded environments.
> >> Initial version provides support for line card type MSN4800-C16. This
> >> type of line card is equipped with:
> >> - Lattice CPLD device, used for system and ports control.
> >> - four Nvidia gearbox devices, used for port splitting.
> >> - FPGA device, used for gearboxes management.
> >> - 16x100G QSFP28 ports.
> >> - hotpswap controllers, voltage regulators, analog-to-digital
> >>   convertors, nvram devices.
> >> - status LED.
> >>
> >> During initialization driver creates:
> >> - line card's I2C tree through "i2c-mux-mlxcpd" driver.
> >> - line card's LED objects through "leds-mlxreg" driver.
> >> - line card's CPLD register space input / output "hwmon" attributes for
> >>   line control and monitoring through "mlxreg-io" driver. These
> >>   attributes provide CPLD and FPAG versioning, control for upgradable
> >>   components burning, NVRAM devices write protection, line card
> >>   revision, line card power consuming, line card reset cause
> >>   indication, etcetera.
> >>
> >> Lattice CPLD device and nvram devices are feeding from auxiliary
> >> power domain and accessible, when line card is powered off. These
> >> devices are connected by line card driver probing routine, invoked
> >> after line card security verification is done by hardware and event
> >> lc#n_verified is received for line card located in slot #n.
> >>
> >> Gearboxes, FPGA, hotpswap controllers, voltage regulators,
> >> analog-to-digital convertors are feeding from main power domain.
> >> These devices are connected after power good event "lc#n_powered" is
> >> received for line card located in slot #n.
> >>
> >> The driver 'mlxreg-lc' is driven by 'mlxreg-hotplug' driver following
> >> relevant "hotplug" events.
> >>
> >> Signed-off-by: Vadim Pasternak <vadimp@xxxxxxxxxx>
> >> Reviewed-by: Michael Shych <michaelsh@xxxxxxxxxx>
> >> ---
> >>  drivers/platform/mellanox/Kconfig     |  12 +
> >>  drivers/platform/mellanox/Makefile    |   1 +
> >>  drivers/platform/mellanox/mlxreg-lc.c | 906
> >> ++++++++++++++++++++++++++
> >>  3 files changed, 919 insertions(+)
> >>  create mode 100644 drivers/platform/mellanox/mlxreg-lc.c
> >>
> >> diff --git a/drivers/platform/mellanox/Kconfig
> >> b/drivers/platform/mellanox/Kconfig
> >> index edd17e1a1f88..d4c5c170bca0 100644
> >> --- a/drivers/platform/mellanox/Kconfig
> >> +++ b/drivers/platform/mellanox/Kconfig
> >> @@ -34,6 +34,18 @@ config MLXREG_IO
> >>  	  to system resets operation, system reset causes monitoring and
> some
> >>  	  kinds of mux selection.
> >>
> >> +config MLXREG_LC
> >> +	tristate "Mellanox line card platform driver support"
> >> +	depends on REGMAP
> >> +	depends on HWMON
> >> +	depends on I2C
> >> +	help
> >> +	  This driver provides support for the Mellanox MSN4800-XX line
> cards,
> >> +	  which are the part of MSN4800 Ethernet modular switch systems
> >> +	  providing a high performance switching solution for Enterprise Data
> >> +	  Centers (EDC) for building Ethernet based clusters, High-
> Performance
> >> +	  Computing (HPC) and embedded environments.
> >> +
> >>  config MLXBF_TMFIFO
> >>  	tristate "Mellanox BlueField SoC TmFifo platform driver"
> >>  	depends on ARM64
> >> diff --git a/drivers/platform/mellanox/Makefile
> >> b/drivers/platform/mellanox/Makefile
> >> index 000ddaa74c98..a4868366ff18 100644
> >> --- a/drivers/platform/mellanox/Makefile
> >> +++ b/drivers/platform/mellanox/Makefile
> >> @@ -8,3 +8,4 @@ obj-$(CONFIG_MLXBF_PMC)		+= mlxbf-
> pmc.o
> >>  obj-$(CONFIG_MLXBF_TMFIFO)	+= mlxbf-tmfifo.o
> >>  obj-$(CONFIG_MLXREG_HOTPLUG)	+= mlxreg-hotplug.o
> >>  obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o
> >> +obj-$(CONFIG_MLXREG_LC) += mlxreg-lc.o
> >> diff --git a/drivers/platform/mellanox/mlxreg-lc.c
> >> b/drivers/platform/mellanox/mlxreg-lc.c
> >> new file mode 100644
> >> index 000000000000..0b7f58feb701
> >> --- /dev/null
> >> +++ b/drivers/platform/mellanox/mlxreg-lc.c
> >> @@ -0,0 +1,906 @@
> >> +// SPDX-License-Identifier: GPL-2.0+
> >> +/*
> >> + * Nvidia line card driver
> >> + *
> >> + * Copyright (C) 2020 Nvidia Technologies Ltd.
> >> + */
> >> +
> >> +#include <linux/device.h>
> >> +#include <linux/i2c.h>
> >> +#include <linux/module.h>
> >> +#include <linux/platform_data/mlxcpld.h> #include
> >> +<linux/platform_data/mlxreg.h> #include <linux/platform_device.h>
> >> +#include <linux/regmap.h>
> >> +
> >> +/* I2C bus IO offsets */
> >> +#define MLXREG_LC_REG_CPLD1_VER_OFFSET		0x2500
> >> +#define MLXREG_LC_REG_FPGA1_VER_OFFSET		0x2501
> >> +#define MLXREG_LC_REG_CPLD1_PN_OFFSET		0x2504
> >> +#define MLXREG_LC_REG_FPGA1_PN_OFFSET		0x2506
> >> +#define MLXREG_LC_REG_RESET_CAUSE_OFFSET	0x251d
> >> +#define MLXREG_LC_REG_LED1_OFFSET		0x2520
> >> +#define MLXREG_LC_REG_GP0_OFFSET		0x252e
> >> +#define MLXREG_LC_REG_FIELD_UPGRADE		0x2534
> >> +#define MLXREG_LC_CHANNEL_I2C_REG		0x25dc
> >> +#define MLXREG_LC_REG_CPLD1_MVER_OFFSET		0x25de
> >> +#define MLXREG_LC_REG_FPGA1_MVER_OFFSET		0x25df
> >> +#define MLXREG_LC_REG_MAX_POWER_OFFSET		0x25f1
> >> +#define MLXREG_LC_REG_CONFIG_OFFSET		0x25fb
> >> +#define MLXREG_LC_REG_MAX			0x3fff
> >> +
> >> +/**
> >> + * enum mlxreg_lc_type - line cards types
> >> + *
> >> + * @MLXREG_LC_SN4800_C16: 100GbE line card with 16 QSFP28 ports;
> */
> >> +enum mlxreg_lc_type {
> >> +	MLXREG_LC_SN4800_C16 = 0x0000,
> >> +};
> >> +
> >> +/**
> >> + * enum mlxreg_lc_state - line cards state
> >> + *
> >> + * @MLXREG_LC_INITIALIZED: line card is initialized;
> >> + * @MLXREG_LC_POWERED: line card is powered;
> >> + * @MLXREG_LC_SYNCED: line card is synchronized between hardware
> and
> >> +firmware;  */ enum mlxreg_lc_state {
> >> +	MLXREG_LC_INITIALIZED = BIT(0),
> >> +	MLXREG_LC_POWERED = BIT(1),
> >> +	MLXREG_LC_SYNCED = BIT(2),
> >> +};
> >> +
> >> +#define MLXREG_LC_CONFIGURED	(MLXREG_LC_INITIALIZED |
> MLXREG_LC_POWERED | MLXREG_LC_SYNCED)
> >> +
> >> +/* mlxreg_lc - device private data
> >> + * @dev: platform device;
> >> + * @lock: line card lock;
> >> + * @par_regmap: parent device regmap handle;
> >> + * @data: pltaform core data;
> >> + * @io_data: register access platform data;
> >> + * @led_data: LED platform data ;
> >> + * @mux_data: MUX platform data;
> >> + * @led: LED device;
> >> + * @io_regs: register access device;
> >> + * @mux_brdinfo: mux configuration;
> >> + * @mux: mux devices;
> >> + * @aux_devs: I2C devices feeding by auxiliary power;
> >> + * @aux_devs_num: number of I2C devices feeding by auxiliary power;
> >> + * @main_devs: I2C devices feeding by main power;
> >> + * @main_devs_num: number of I2C devices feeding by main power;
> >> + * @state: line card state;
> >> + */
> >> +struct mlxreg_lc {
> >> +	struct device *dev;
> >> +	struct mutex lock; /* line card access lock */
> >> +	void *par_regmap;
> >> +	struct mlxreg_core_data *data;
> >> +	struct mlxreg_core_platform_data *io_data;
> >> +	struct mlxreg_core_platform_data *led_data;
> >> +	struct mlxcpld_mux_plat_data *mux_data;
> >> +	struct platform_device *led;
> >> +	struct platform_device *io_regs;
> >> +	struct i2c_board_info *mux_brdinfo;
> >> +	struct platform_device *mux;
> >> +	struct mlxreg_hotplug_device *aux_devs;
> >> +	int aux_devs_num;
> >> +	struct mlxreg_hotplug_device *main_devs;
> >> +	int main_devs_num;
> >> +	enum mlxreg_lc_state state;
> >> +};
> >> +
> >> +static bool mlxreg_lc_writeable_reg(struct device *dev, unsigned int
> >> +reg) {
> >> +	switch (reg) {
> >> +	case MLXREG_LC_REG_LED1_OFFSET:
> >> +	case MLXREG_LC_REG_GP0_OFFSET:
> >> +	case MLXREG_LC_REG_FIELD_UPGRADE:
> >> +	case MLXREG_LC_CHANNEL_I2C_REG:
> >> +		return true;
> >> +	}
> >> +	return false;
> >> +}
> >> +
> >> +static bool mlxreg_lc_readable_reg(struct device *dev, unsigned int
> >> +reg) {
> >> +	switch (reg) {
> >> +	case MLXREG_LC_REG_CPLD1_VER_OFFSET:
> >> +	case MLXREG_LC_REG_FPGA1_VER_OFFSET:
> >> +	case MLXREG_LC_REG_CPLD1_PN_OFFSET:
> >> +	case MLXREG_LC_REG_FPGA1_PN_OFFSET:
> >> +	case MLXREG_LC_REG_RESET_CAUSE_OFFSET:
> >> +	case MLXREG_LC_REG_LED1_OFFSET:
> >> +	case MLXREG_LC_REG_GP0_OFFSET:
> >> +	case MLXREG_LC_REG_FIELD_UPGRADE:
> >> +	case MLXREG_LC_CHANNEL_I2C_REG:
> >> +	case MLXREG_LC_REG_CPLD1_MVER_OFFSET:
> >> +	case MLXREG_LC_REG_FPGA1_MVER_OFFSET:
> >> +	case MLXREG_LC_REG_MAX_POWER_OFFSET:
> >> +	case MLXREG_LC_REG_CONFIG_OFFSET:
> >> +		return true;
> >> +	}
> >> +	return false;
> >> +}
> >> +
> >> +static bool mlxreg_lc_volatile_reg(struct device *dev, unsigned int
> >> +reg) {
> >> +	switch (reg) {
> >> +	case MLXREG_LC_REG_CPLD1_VER_OFFSET:
> >> +	case MLXREG_LC_REG_FPGA1_VER_OFFSET:
> >> +	case MLXREG_LC_REG_CPLD1_PN_OFFSET:
> >> +	case MLXREG_LC_REG_FPGA1_PN_OFFSET:
> >> +	case MLXREG_LC_REG_RESET_CAUSE_OFFSET:
> >> +	case MLXREG_LC_REG_LED1_OFFSET:
> >> +	case MLXREG_LC_REG_GP0_OFFSET:
> >> +	case MLXREG_LC_REG_FIELD_UPGRADE:
> >> +	case MLXREG_LC_CHANNEL_I2C_REG:
> >> +	case MLXREG_LC_REG_CPLD1_MVER_OFFSET:
> >> +	case MLXREG_LC_REG_FPGA1_MVER_OFFSET:
> >> +	case MLXREG_LC_REG_MAX_POWER_OFFSET:
> >> +	case MLXREG_LC_REG_CONFIG_OFFSET:
> >> +		return true;
> >> +	}
> >> +	return false;
> >> +}
> >> +
> >> +static const struct reg_default mlxreg_lc_regmap_default[] = {
> >> +	{ MLXREG_LC_CHANNEL_I2C_REG, 0x00 }, };
> >> +
> >> +/* Configuration for the register map of a device with 2 bytes
> >> +address space. */ static const struct regmap_config
> mlxreg_lc_regmap_conf = {
> >> +	.reg_bits = 16,
> >> +	.val_bits = 8,
> >> +	.max_register = MLXREG_LC_REG_MAX,
> >> +	.cache_type = REGCACHE_FLAT,
> >> +	.writeable_reg = mlxreg_lc_writeable_reg,
> >> +	.readable_reg = mlxreg_lc_readable_reg,
> >> +	.volatile_reg = mlxreg_lc_volatile_reg,
> >> +	.reg_defaults = mlxreg_lc_regmap_default,
> >> +	.num_reg_defaults = ARRAY_SIZE(mlxreg_lc_regmap_default),
> >> +};
> >> +
> >> +/* Default channels vector.
> >> + * It contains only the channels, which physically connected to the
> >> +devices,
> >> + * empty channels are skipped.
> >> + */
> >> +static int mlxreg_lc_chan[] = {
> >> +	0x04, 0x05, 0x06, 0x07, 0x08, 0x10, 0x20, 0x21, 0x22, 0x23, 0x40, 0x41,
> >> +	0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
> >> +	0x4e, 0x4f
> >> +};
> >> +
> >> +/* Defaul mux configuration. */
> >> +static struct mlxcpld_mux_plat_data mlxreg_lc_mux_data[] = {
> >> +	{
> >> +		.chan_ids = mlxreg_lc_chan,
> >> +		.num_adaps = ARRAY_SIZE(mlxreg_lc_chan),
> >> +		.sel_reg_addr = MLXREG_LC_CHANNEL_I2C_REG,
> >> +		.reg_size = 2,
> >> +	},
> >> +};
> >> +
> >> +/* Defaul mux board info. */
> >> +static struct i2c_board_info mlxreg_lc_mux_brdinfo = {
> >> +	I2C_BOARD_INFO("i2c-mux-mlxcpld", 0x32), };
> >> +
> >> +/* Line card default auxiliary power static devices. */ static
> >> +struct i2c_board_info mlxreg_lc_aux_pwr_devices[] = {
> >> +	{
> >> +		I2C_BOARD_INFO("24c32", 0x51),
> >> +	},
> >> +	{
> >> +		I2C_BOARD_INFO("24c32", 0x51),
> >> +	},
> >> +};
> >> +
> >> +/* Line card default auxiliary power board info. */ static struct
> >> +mlxreg_hotplug_device mlxreg_lc_aux_pwr_brdinfo[] = {
> >> +	{
> >> +		.brdinfo = &mlxreg_lc_aux_pwr_devices[0],
> >> +		.nr = 3,
> >> +	},
> >> +	{
> >> +		.brdinfo = &mlxreg_lc_aux_pwr_devices[1],
> >> +		.nr = 4,
> >> +	},
> >> +};
> >> +
> >> +/* Line card default main power static devices. */ static struct
> >> +i2c_board_info mlxreg_lc_main_pwr_devices[] = {
> >> +	{
> >> +		I2C_BOARD_INFO("mp2975", 0x62),
> >> +	},
> >> +	{
> >> +		I2C_BOARD_INFO("mp2975", 0x64),
> >> +	},
> >> +	{
> >> +		I2C_BOARD_INFO("max11603", 0x6d),
> >> +	},
> >> +	{
> >> +		I2C_BOARD_INFO("lm25066", 0x15),
> >> +	},
> >> +};
> >> +
> >> +/* Line card default main power board info. */ static struct
> >> +mlxreg_hotplug_device mlxreg_lc_main_pwr_brdinfo[] = {
> >> +	{
> >> +		.brdinfo = &mlxreg_lc_main_pwr_devices[0],
> >> +		.nr = 0,
> >> +	},
> >> +	{
> >> +		.brdinfo = &mlxreg_lc_main_pwr_devices[1],
> >> +		.nr = 0,
> >> +	},
> >> +	{
> >> +		.brdinfo = &mlxreg_lc_main_pwr_devices[2],
> >> +		.nr = 1,
> >> +	},
> >> +	{
> >> +		.brdinfo = &mlxreg_lc_main_pwr_devices[3],
> >> +		.nr = 2,
> >> +	},
> >> +};
> >> +
> >> +/* LED default data. */
> >> +static struct mlxreg_core_data mlxreg_lc_led_data[] = {
> >> +	{
> >> +		.label = "status:green",
> >> +		.reg = MLXREG_LC_REG_LED1_OFFSET,
> >> +		.mask = GENMASK(7, 4),
> >> +	},
> >> +	{
> >> +		.label = "status:orange",
> >> +		.reg = MLXREG_LC_REG_LED1_OFFSET,
> >> +		.mask = GENMASK(7, 4),
> >> +	},
> >> +};
> >> +
> >> +static struct mlxreg_core_platform_data mlxreg_lc_led = {
> >> +	.identity = "pci",
> >> +	.data = mlxreg_lc_led_data,
> >> +	.counter = ARRAY_SIZE(mlxreg_lc_led_data), };
> >> +
> >> +/* Default register access data. */
> >> +static struct mlxreg_core_data mlxreg_lc_io_data[] = {
> >> +	{
> >> +		.label = "cpld1_version",
> >> +		.reg = MLXREG_LC_REG_CPLD1_VER_OFFSET,
> >> +		.bit = GENMASK(7, 0),
> >> +		.mode = 0444,
> >> +	},
> >> +	{
> >> +		.label = "fpga1_version",
> >> +		.reg = MLXREG_LC_REG_FPGA1_VER_OFFSET,
> >> +		.bit = GENMASK(7, 0),
> >> +		.mode = 0444,
> >> +	},
> >> +	{
> >> +		.label = "cpld1_pn",
> >> +		.reg = MLXREG_LC_REG_CPLD1_PN_OFFSET,
> >> +		.bit = GENMASK(15, 0),
> >> +		.mode = 0444,
> >> +		.regnum = 2,
> >> +	},
> >> +	{
> >> +		.label = "fpga1_pn",
> >> +		.reg = MLXREG_LC_REG_FPGA1_PN_OFFSET,
> >> +		.bit = GENMASK(15, 0),
> >> +		.mode = 0444,
> >> +		.regnum = 2,
> >> +	},
> >> +	{
> >> +		.label = "cpld1_version_min",
> >> +		.reg = MLXREG_LC_REG_CPLD1_MVER_OFFSET,
> >> +		.bit = GENMASK(7, 0),
> >> +		.mode = 0444,
> >> +	},
> >> +	{
> >> +		.label = "fpga1_version_min",
> >> +		.reg = MLXREG_LC_REG_FPGA1_MVER_OFFSET,
> >> +		.bit = GENMASK(7, 0),
> >> +		.mode = 0444,
> >> +	},
> >> +	{
> >> +		.label = "reset_fpga_not_done",
> >> +		.reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET,
> >> +		.mask = GENMASK(7, 0) & ~BIT(1),
> >> +		.mode = 0444,
> >> +	},
> >> +	{
> >> +		.label = "reset_aux_pwr_or_ref",
> >> +		.reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET,
> >> +		.mask = GENMASK(7, 0) & ~BIT(2),
> >> +		.mode = 0444,
> >> +	},
> >> +	{
> >> +		.label = "reset_dc_dc_pwr_fail",
> >> +		.reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET,
> >> +		.mask = GENMASK(7, 0) & ~BIT(3),
> >> +		.mode = 0444,
> >> +	},
> >> +	{
> >> +		.label = "reset_from_chassis",
> >> +		.reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET,
> >> +		.mask = GENMASK(7, 0) & ~BIT(4),
> >> +		.mode = 0444,
> >> +	},
> >> +	{
> >> +		.label = "reset_pwr_off_from_chassis",
> >> +		.reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET,
> >> +		.mask = GENMASK(7, 0) & ~BIT(5),
> >> +		.mode = 0444,
> >> +	},
> >> +	{
> >> +		.label = "reset_line_card",
> >> +		.reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET,
> >> +		.mask = GENMASK(7, 0) & ~BIT(6),
> >> +		.mode = 0444,
> >> +	},
> >> +	{
> >> +		.label = "reset_line_card_pwr_en",
> >> +		.reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET,
> >> +		.mask = GENMASK(7, 0) & ~BIT(7),
> >> +		.mode = 0444,
> >> +	},
> >> +	{
> >> +		.label = "cpld_upgrade_en",
> >> +		.reg = MLXREG_LC_REG_FIELD_UPGRADE,
> >> +		.mask = GENMASK(7, 0) & ~BIT(0),
> >> +		.mode = 0644,
> >> +		.secured = 1,
> >> +	},
> >> +	{
> >> +		.label = "fpga_upgrade_en",
> >> +		.reg = MLXREG_LC_REG_FIELD_UPGRADE,
> >> +		.mask = GENMASK(7, 0) & ~BIT(1),
> >> +		.mode = 0644,
> >> +		.secured = 1,
> >> +	},
> >> +	{
> >> +		.label = "qsfp_pwr_en",
> >> +		.reg = MLXREG_LC_REG_GP0_OFFSET,
> >> +		.mask = GENMASK(7, 0) & ~BIT(0),
> >> +		.mode = 0644,
> >> +	},
> >> +	{
> >> +		.label = "vpd_wp",
> >> +		.reg = MLXREG_LC_REG_GP0_OFFSET,
> >> +		.mask = GENMASK(7, 0) & ~BIT(3),
> >> +		.mode = 0644,
> >> +		.secured = 1,
> >> +	},
> >> +	{
> >> +		.label = "agb_spi_burn_en",
> >> +		.reg = MLXREG_LC_REG_GP0_OFFSET,
> >> +		.mask = GENMASK(7, 0) & ~BIT(5),
> >> +		.mode = 0644,
> >> +		.secured = 1,
> >> +	},
> >> +	{
> >> +		.label = "fpga_spi_burn_en",
> >> +		.reg = MLXREG_LC_REG_GP0_OFFSET,
> >> +		.mask = GENMASK(7, 0) & ~BIT(6),
> >> +		.mode = 0644,
> >> +		.secured = 1,
> >> +	},
> >> +	{
> >> +		.label = "max_power",
> >> +		.reg = MLXREG_LC_REG_MAX_POWER_OFFSET,
> >> +		.bit = GENMASK(15, 0),
> >> +		.mode = 0444,
> >> +		.regnum = 2,
> >> +	},
> >> +	{
> >> +		.label = "config",
> >> +		.reg = MLXREG_LC_REG_CONFIG_OFFSET,
> >> +		.bit = GENMASK(15, 0),
> >> +		.mode = 0444,
> >> +		.regnum = 2,
> >> +	},
> >> +};
> >> +
> >> +static struct mlxreg_core_platform_data mlxreg_lc_regs_io = {
> >> +	.data = mlxreg_lc_io_data,
> >> +	.counter = ARRAY_SIZE(mlxreg_lc_io_data), };
> >> +
> >> +static int
> >> +mlxreg_lc_create_static_devices(struct mlxreg_lc *mlxreg_lc, struct
> mlxreg_hotplug_device *devs,
> >> +				int size)
> >> +{
> >> +	struct mlxreg_hotplug_device *dev = devs;
> >> +	int i;
> >> +
> >> +	/* Create static I2C device feeding by auxiliary or main power. */
> >> +	for (i = 0; i < size; i++, dev++) {
> >> +		dev->client = i2c_new_client_device(dev->adapter, dev-
> >brdinfo);
> >> +		if (IS_ERR(dev->client)) {
> >> +			dev_err(mlxreg_lc->dev, "Failed to create client %s
> at bus %d at addr 0x%02x\n",
> >> +				dev->brdinfo->type, dev->nr, dev->brdinfo-
> >addr);
> >> +
> >> +			dev->adapter = NULL;
> >> +			goto fail_create_static_devices;
> >> +		}
> >> +	}
> >> +
> >> +	return 0;
> >> +
> >> +fail_create_static_devices:
> >> +	while (--i >= 0) {
> >> +		dev = devs + i;
> >> +		i2c_unregister_device(dev->client);
> >> +		dev->client = NULL;
> >> +	}
> >> +	return IS_ERR(dev->client);
> >> +}
> >> +
> >> +static void
> >> +mlxreg_lc_destroy_static_devices(struct mlxreg_lc *mlxreg_lc, struct
> mlxreg_hotplug_device *devs,
> >> +				 int size)
> >> +{
> >> +	struct mlxreg_hotplug_device *dev = devs;
> >> +	int i;
> >> +
> >> +	/* Destroy static I2C device feeding by auxiliary or main power. */
> >> +	for (i = 0; i < size; i++, dev++) {
> >> +		if (dev->client) {
> >> +			i2c_unregister_device(dev->client);
> >> +			dev->client = NULL;
> >> +		}
> >> +	}
> >> +}
> >> +
> >> +static int mlxreg_lc_power_on_off(struct mlxreg_lc *mlxreg_lc, u8
> >> +action) {
> >> +	u32 regval;
> >> +	int err;
> >> +
> >> +	mutex_lock(&mlxreg_lc->lock);
> >> +
> >> +	err = regmap_read(mlxreg_lc->par_regmap, mlxreg_lc->data-
> >reg_pwr, &regval);
> >> +	if (err)
> >> +		goto regmap_read_fail;
> >> +
> >> +	if (action)
> >> +		regval |= BIT(mlxreg_lc->data->slot - 1);
> >> +	else
> >> +		regval &= ~BIT(mlxreg_lc->data->slot - 1);
> >> +
> >> +	err = regmap_write(mlxreg_lc->par_regmap, mlxreg_lc->data-
> >reg_pwr,
> >> +regval);
> >> +
> >> +regmap_read_fail:
> >> +	mutex_unlock(&mlxreg_lc->lock);
> >> +	return err;
> >> +}
> >> +
> >> +static int mlxreg_lc_enable_disable(struct mlxreg_lc *mlxreg_lc,
> >> +bool action) {
> >> +	u32 regval;
> >> +	int err;
> >> +
> >> +	/*
> >> +	 * Hardware holds the line card after powering on in the disabled
> state. Holding line card
> >> +	 * in disabled state protects access to the line components, like FPGA
> and gearboxes.
> >> +	 * Line card should be enabled in order to get it in operational state.
> Line card could be
> >> +	 * disabled for moving it to non-operational state. Enabling line card
> does not affect the
> >> +	 * line card which is already has been enabled. Disabling does not
> affect the disabled line
> >> +	 * card.
> >> +	 */
> >> +	mutex_lock(&mlxreg_lc->lock);
> >> +
> >> +	err = regmap_read(mlxreg_lc->par_regmap, mlxreg_lc->data-
> >reg_ena, &regval);
> >> +	if (err)
> >> +		goto regmap_read_fail;
> >> +
> >> +	if (action)
> >> +		regval |= BIT(mlxreg_lc->data->slot - 1);
> >> +	else
> >> +		regval &= ~BIT(mlxreg_lc->data->slot - 1);
> >> +
> >> +	err = regmap_write(mlxreg_lc->par_regmap, mlxreg_lc->data-
> >reg_ena,
> >> +regval);
> >> +
> >> +regmap_read_fail:
> >> +	mutex_unlock(&mlxreg_lc->lock);
> >> +	return err;
> >> +}
> >> +
> >> +static int
> >> +mlxreg_lc_sn4800_c16_config_init(struct mlxreg_lc *mlxreg_lc, void
> *regmap,
> >> +				 struct mlxreg_core_data *data)
> >> +{
> >> +	struct device *dev = &data->hpdev.client->dev;
> >> +
> >> +	/* Set line card configuration according to the type. */
> >> +	mlxreg_lc->mux_data = mlxreg_lc_mux_data;
> >> +	mlxreg_lc->io_data = &mlxreg_lc_regs_io;
> >> +	mlxreg_lc->led_data = &mlxreg_lc_led;
> >> +	mlxreg_lc->mux_brdinfo = &mlxreg_lc_mux_brdinfo;
> >> +
> >> +	mlxreg_lc->aux_devs = devm_kmemdup(dev,
> mlxreg_lc_aux_pwr_brdinfo,
> >> +
> sizeof(mlxreg_lc_aux_pwr_brdinfo), GFP_KERNEL);
> >> +	if (!mlxreg_lc->aux_devs)
> >> +		return -ENOMEM;
> >> +	mlxreg_lc->aux_devs_num =
> ARRAY_SIZE(mlxreg_lc_aux_pwr_brdinfo);
> >> +	mlxreg_lc->main_devs = devm_kmemdup(dev,
> mlxreg_lc_main_pwr_brdinfo,
> >> +
> sizeof(mlxreg_lc_main_pwr_brdinfo), GFP_KERNEL);
> >> +	if (!mlxreg_lc->main_devs)
> >> +		return -ENOMEM;
> >> +	mlxreg_lc->main_devs_num =
> ARRAY_SIZE(mlxreg_lc_main_pwr_brdinfo);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static void
> >> +mlxreg_lc_state_update(struct mlxreg_lc *mlxreg_lc, enum
> >> +mlxreg_lc_state state, u8 action) {
> >> +	mutex_lock(&mlxreg_lc->lock);
> >> +
> >> +	if (action)
> >> +		mlxreg_lc->state |= state;
> >> +	else
> >> +		mlxreg_lc->state &= ~state;
> >> +
> >> +	mutex_unlock(&mlxreg_lc->lock);
> >> +}
> >> +
> >> +/*
> >> + * Callback is to be called from mlxreg-hotplug driver to notify
> >> +about line card about received
> >> + * event.
> >> + */
> >> +static int mlxreg_lc_event_handler(void *handle, enum
> >> +mlxreg_hotplug_kind kind, u8 action) {
> >> +	struct mlxreg_lc *mlxreg_lc = handle;
> >> +	int err = 0;
> >> +
> >> +	dev_info(mlxreg_lc->dev, "linecard#%d state %d event kind %d
> action %d\n",
> >> +		 mlxreg_lc->data->slot, mlxreg_lc->state, kind, action);
> >> +
> >> +	if (!(mlxreg_lc->state & MLXREG_LC_INITIALIZED))
> >> +		return 0;
> >> +
> >> +	switch (kind) {
> >> +	case MLXREG_HOTPLUG_LC_SYNCED:
> >> +		/*
> >> +		 * Synchronization event - hardware and firmware are
> synchronized. Power on/off
> >> +		 * line card - to allow/disallow main power source.
> >> +		 */
> >> +		mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_SYNCED,
> action);
> >> +		/* Power line card if it is not powered yet. */
> >> +		if (!(mlxreg_lc->state & MLXREG_LC_POWERED) && action) {
> >> +			err = mlxreg_lc_power_on_off(mlxreg_lc, 1);
> >> +			if (err)
> >> +				return err;
> >> +		}
> >> +		/* In case line card is configured - enable it. */
> >> +		if (mlxreg_lc->state & MLXREG_LC_CONFIGURED && action)
> >> +			err = mlxreg_lc_enable_disable(mlxreg_lc, 1);
> >> +		break;
> >> +	case MLXREG_HOTPLUG_LC_POWERED:
> >> +		/* Power event - attach or de-attach line card device feeding
> by the main power. */
> >> +		if (action) {
> >> +			/* Do not create devices, if line card is already
> powered. */
> >> +			if (mlxreg_lc->state & MLXREG_LC_POWERED) {
> >> +				/* In case line card is configured - enable it.
> */
> >> +				if (mlxreg_lc->state &
> MLXREG_LC_CONFIGURED)
> >> +					err =
> mlxreg_lc_enable_disable(mlxreg_lc, 1);
> >> +				return err;
> >> +			}
> >> +			err = mlxreg_lc_create_static_devices(mlxreg_lc,
> mlxreg_lc->main_devs,
> >> +							      mlxreg_lc-
> >main_devs_num);
> >> +			if (err)
> >> +				return err;
> >> +
> >> +			/* In case line card is already in ready state - enable
> it. */
> >> +			if (mlxreg_lc->state & MLXREG_LC_CONFIGURED)
> >> +				err = mlxreg_lc_enable_disable(mlxreg_lc,
> 1);
> >> +		} else {
> >> +			mlxreg_lc_destroy_static_devices(mlxreg_lc,
> mlxreg_lc->main_devs,
> >> +							 mlxreg_lc-
> >main_devs_num);
> >> +		}
> >> +		mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_POWERED,
> action);
> >> +		break;
> >> +	case MLXREG_HOTPLUG_LC_READY:
> >> +		/*
> >> +		 * Ready event – enable line card by releasing it from reset or
> disable it by put
> >> +		 * to reset state.
> >> +		 */
> >> +		err = mlxreg_lc_enable_disable(mlxreg_lc, !!action);
> >> +		break;
> >> +	case MLXREG_HOTPLUG_LC_THERMAL:
> >> +		/* Thermal shutdown event – power off line card. */
> >> +		if (action)
> >> +			err = mlxreg_lc_power_on_off(mlxreg_lc, 0);
> >> +		break;
> >> +	default:
> >> +		break;
> >> +	}
> >> +
> >> +	return err;
> >> +}
> >> +
> >> +/*
> >> + * Callback is to be called from i2c-mux-mlxcpld driver to indicate
> >> +that all adapter devices has
> >> + * been created.
> >> + */
> >> +static int mlxreg_lc_completion_notify(void *handle, struct i2c_adapter
> *parent,
> >> +				       struct i2c_adapter *adapters[]) {
> >> +	struct mlxreg_hotplug_device *main_dev, *aux_dev;
> >> +	struct mlxreg_lc *mlxreg_lc = handle;
> >> +	u32 regval;
> >> +	int i, err;
> >> +
> >> +	/* Update I2C devices feeding by auxiliary power. */
> >> +	aux_dev = mlxreg_lc->aux_devs;
> >> +	for (i = 0; i < mlxreg_lc->aux_devs_num; i++, aux_dev++) {
> >> +		aux_dev->adapter = adapters[aux_dev->nr];
> >> +		aux_dev->nr = adapters[aux_dev->nr]->nr;
> >> +	}
> >> +
> >> +	err = mlxreg_lc_create_static_devices(mlxreg_lc, mlxreg_lc-
> >aux_devs,
> >> +					      mlxreg_lc->aux_devs_num);
> >> +	if (err)
> >> +		return err;
> >> +
> >> +	/* Update I2C devices feeding by main power. */
> >> +	main_dev = mlxreg_lc->main_devs;
> >> +	for (i = 0; i < mlxreg_lc->main_devs_num; i++, main_dev++) {
> >> +		main_dev->adapter = adapters[main_dev->nr];
> >> +		main_dev->nr = adapters[main_dev->nr]->nr;
> >> +	}
> >> +
> >> +	/* Verify if line card is powered. */
> >> +	err = regmap_read(mlxreg_lc->par_regmap, mlxreg_lc->data-
> >reg_pwr, &regval);
> >> +	if (err)
> >> +		goto mlxreg_lc_regmap_read_power_fail;
> >> +
> >> +	if (regval & mlxreg_lc->data->mask) {
> >> +		err = mlxreg_lc_create_static_devices(mlxreg_lc, mlxreg_lc-
> >main_devs,
> >> +						      mlxreg_lc-
> >main_devs_num);
> >> +		if (err)
> >> +			goto mlxreg_lc_create_static_devices_failed;
> >> +
> >> +		mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_POWERED,
> 1);
> >> +	}
> >> +
> >> +	/* Verify if line card is synchronized. */
> >> +	err = regmap_read(mlxreg_lc->par_regmap, mlxreg_lc->data-
> >reg_sync, &regval);
> >> +	if (err)
> >> +		goto mlxreg_lc_regmap_read_sync_fail;
> >> +
> >> +	/* Power on line card if necessary. */
> >> +	if (regval & mlxreg_lc->data->mask) {
> >> +		mlxreg_lc->state |= MLXREG_LC_SYNCED;
> >> +		mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_SYNCED, 1);
> >> +		if (mlxreg_lc->state & ~MLXREG_LC_POWERED) {
> >> +			err = mlxreg_lc_power_on_off(mlxreg_lc, 1);
> >> +			if (err)
> >> +				goto mlxreg_lc_regmap_power_on_off_fail;
> >> +		}
> >> +	}
> >> +
> >> +	mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_INITIALIZED, 1);
> >> +
> >> +	return 0;
> >> +
> >> +mlxreg_lc_regmap_power_on_off_fail:
> >> +mlxreg_lc_regmap_read_sync_fail:
> >> +	if (mlxreg_lc->state & MLXREG_LC_POWERED)
> >> +		mlxreg_lc_destroy_static_devices(mlxreg_lc, mlxreg_lc-
> >main_devs,
> >> +						 mlxreg_lc-
> >main_devs_num);
> >> +mlxreg_lc_create_static_devices_failed:
> >> +	mlxreg_lc_destroy_static_devices(mlxreg_lc, mlxreg_lc->aux_devs,
> >> +mlxreg_lc->aux_devs_num);
> >> +mlxreg_lc_regmap_read_power_fail:
> >> +	return err;
> >> +}
> >> +
> >> +static int
> >> +mlxreg_lc_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap,
> >> +		      struct mlxreg_core_data *data) {
> >> +	struct device *dev = &data->hpdev.client->dev;
> >> +	int lsb, err;
> >> +	u32 regval;
> >> +
> >> +	/* Validate line card type. */
> >> +	err = regmap_read(regmap, MLXREG_LC_REG_CONFIG_OFFSET,
> &lsb);
> >> +	err = (!err) ? regmap_read(regmap,
> MLXREG_LC_REG_CONFIG_OFFSET, &regval) : err;
> >> +	if (err)
> >> +		return err;
> >> +	regval = (regval & GENMASK(7, 0)) << 8 | (lsb & GENMASK(7, 0));
> >> +	switch (regval) {
> >> +	case MLXREG_LC_SN4800_C16:
> >> +		err = mlxreg_lc_sn4800_c16_config_init(mlxreg_lc, regmap,
> data);
> >> +		if (err)
> >> +			return err;
> >> +		break;
> >> +	default:
> >> +		return -ENODEV;
> >> +	}
> >> +
> >> +	/* Create mux infrastructure. */
> >> +	mlxreg_lc->mux_data->handle = mlxreg_lc;
> >> +	mlxreg_lc->mux_data->completion_notify =
> mlxreg_lc_completion_notify;
> >> +	mlxreg_lc->mux_brdinfo->platform_data = mlxreg_lc->mux_data;
> >> +	mlxreg_lc->mux = platform_device_register_resndata(dev, "i2c-
> mux-mlxcpld", data->hpdev.nr,
> >> +							   NULL, 0, mlxreg_lc-
> >mux_data,
> >> +							   sizeof(*mlxreg_lc-
> >mux_data));
> >> +	if (IS_ERR(mlxreg_lc->mux))
> >> +		return PTR_ERR(mlxreg_lc->mux);
> >> +
> >> +	/* Register IO access driver. */
> >> +	if (mlxreg_lc->io_data) {
> >> +		mlxreg_lc->io_data->regmap = regmap;
> >> +		mlxreg_lc->io_regs =
> >> +		platform_device_register_resndata(dev, "mlxreg-io", data-
> >hpdev.nr, NULL, 0,
> >> +						  mlxreg_lc->io_data,
> sizeof(*mlxreg_lc->io_data));
> >> +		if (IS_ERR(mlxreg_lc->io_regs)) {
> >> +			err = PTR_ERR(mlxreg_lc->io_regs);
> >> +			goto fail_register_io;
> >> +		}
> >> +	}
> >> +
> >> +	/* Register LED driver. */
> >> +	if (mlxreg_lc->led_data) {
> >> +		mlxreg_lc->led_data->regmap = regmap;
> >> +		mlxreg_lc->led =
> >> +		platform_device_register_resndata(dev, "leds-mlxreg",
> data->hpdev.nr, NULL, 0,
> >> +						  mlxreg_lc->led_data,
> >> +						  sizeof(*mlxreg_lc-
> >led_data));
> >> +		if (IS_ERR(mlxreg_lc->led)) {
> >> +			err = PTR_ERR(mlxreg_lc->led);
> >> +			goto fail_register_led;
> >> +		}
> >> +	}
> >> +
> >> +	return 0;
> >> +
> >> +fail_register_led:
> >> +	if (mlxreg_lc->io_regs)
> >> +		platform_device_unregister(mlxreg_lc->io_regs);
> >> +fail_register_io:
> >> +	if (mlxreg_lc->mux)
> >> +		platform_device_unregister(mlxreg_lc->mux);
> >> +
> >> +	return err;
> >> +}
> >> +
> >> +static void mlxreg_lc_config_exit(struct mlxreg_lc *mlxreg_lc) {
> >> +	/* Unregister LED driver. */
> >> +	if (mlxreg_lc->led)
> >> +		platform_device_unregister(mlxreg_lc->led);
> >> +	/* Unregister IO access driver. */
> >> +	if (mlxreg_lc->io_regs)
> >> +		platform_device_unregister(mlxreg_lc->io_regs);
> >> +	/* Remove mux infrastructure. */
> >> +	if (mlxreg_lc->mux)
> >> +		platform_device_unregister(mlxreg_lc->mux);
> >> +}
> >> +
> >> +static int mlxreg_lc_probe(struct platform_device *pdev) {
> >> +	struct mlxreg_core_hotplug_platform_data *par_pdata;
> >> +	struct mlxreg_core_data *data;
> >> +	struct mlxreg_lc *mlxreg_lc;
> >> +	void *regmap;
> >> +	int i, err;
> >> +
> >> +	data = dev_get_platdata(&pdev->dev);
> >> +	if (!data)
> >> +		return -EINVAL;
> >> +
> >> +	mlxreg_lc = devm_kzalloc(&pdev->dev, sizeof(*mlxreg_lc),
> GFP_KERNEL);
> >> +	if (!mlxreg_lc)
> >> +		return -ENOMEM;
> >> +
> >> +	mutex_init(&mlxreg_lc->lock);
> >> +	/* Set event notification callback. */
> >> +	if (data->notifier) {
> >> +		data->notifier->user_handler = mlxreg_lc_event_handler;
> >> +		data->notifier->handle = mlxreg_lc;
> >> +	}
> >> +	data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr);
> >> +	if (!data->hpdev.adapter) {
> >> +		dev_err(&pdev->dev, "Failed to get adapter for bus %d\n",
> >> +			data->hpdev.nr);
> >> +		return -EFAULT;
> >> +	}
> >> +
> >> +	/* Create device at the top of line card I2C tree.*/
> >> +	data->hpdev.client = i2c_new_client_device(data->hpdev.adapter,
> >> +						   data->hpdev.brdinfo);
> >> +	if (IS_ERR(data->hpdev.client)) {
> >> +		dev_err(&pdev->dev, "Failed to create client %s at bus %d at
> addr 0x%02x\n",
> >> +			data->hpdev.brdinfo->type, data->hpdev.nr,
> >> +data->hpdev.brdinfo->addr);
> >> +
> >> +		i2c_put_adapter(data->hpdev.adapter);
> >> +		data->hpdev.adapter = NULL;
> >> +		return PTR_ERR(data->hpdev.client);
> >> +	}
> >> +
> >> +	regmap = devm_regmap_init_i2c(data->hpdev.client,
> >> +				      &mlxreg_lc_regmap_conf);
> >> +	if (IS_ERR(regmap)) {
> >> +		err = PTR_ERR(regmap);
> >> +		goto mlxreg_lc_probe_fail;
> >> +	}
> >> +
> >> +	/* Set default registers. */
> >> +	for (i = 0; i < mlxreg_lc_regmap_conf.num_reg_defaults; i++) {
> >> +		err = regmap_write(regmap,
> mlxreg_lc_regmap_default[i].reg,
> >> +				   mlxreg_lc_regmap_default[i].def);
> >> +		if (err)
> >> +			goto mlxreg_lc_probe_fail;
> >> +	}
> >> +
> >> +	/* Sync registers with hardware. */
> >> +	regcache_mark_dirty(regmap);
> >> +	err = regcache_sync(regmap);
> >> +	if (err)
> >> +		goto mlxreg_lc_probe_fail;
> >> +
> >> +	par_pdata = data->hpdev.brdinfo->platform_data;
> >> +	mlxreg_lc->par_regmap = par_pdata->regmap;
> >> +	mlxreg_lc->data = data;
> >> +	mlxreg_lc->dev = &pdev->dev;
> >> +	platform_set_drvdata(pdev, mlxreg_lc);
> >> +
> >> +	/* Configure line card. */
> >> +	err = mlxreg_lc_config_init(mlxreg_lc, regmap, data);
> >> +	if (err)
> >> +		goto mlxreg_lc_probe_fail;
> >> +
> >> +	return err;
> >> +
> >> +mlxreg_lc_probe_fail:
> >> +	i2c_put_adapter(data->hpdev.adapter);
> >> +	return err;
> >> +}
> >> +
> >> +static int mlxreg_lc_remove(struct platform_device *pdev) {
> >> +	struct mlxreg_core_data *data = dev_get_platdata(&pdev->dev);
> >> +	struct mlxreg_lc *mlxreg_lc = platform_get_drvdata(pdev);
> >> +
> >> +	/* Clear event notification callback. */
> >> +	if (data->notifier) {
> >> +		data->notifier->user_handler = NULL;
> >> +		data->notifier->handle = NULL;
> >> +	}
> >> +
> >> +	/* Destroy static I2C device feeding by main power. */
> >> +	mlxreg_lc_destroy_static_devices(mlxreg_lc, mlxreg_lc->main_devs,
> >> +					 mlxreg_lc->main_devs_num);
> >> +	/* Destroy static I2C device feeding by auxiliary power. */
> >> +	mlxreg_lc_destroy_static_devices(mlxreg_lc, mlxreg_lc->aux_devs,
> mlxreg_lc->aux_devs_num);
> >> +	/* Unregister underlying drivers. */
> >> +	mlxreg_lc_config_exit(mlxreg_lc);
> >> +	if (data->hpdev.client) {
> >> +		i2c_unregister_device(data->hpdev.client);
> >> +		data->hpdev.client = NULL;
> >> +		i2c_put_adapter(data->hpdev.adapter);
> >> +		data->hpdev.adapter = NULL;
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static struct platform_driver mlxreg_lc_driver = {
> >> +	.probe = mlxreg_lc_probe,
> >> +	.remove = mlxreg_lc_remove,
> >> +	.driver = {
> >> +		.name = "mlxreg-lc",
> >> +	},
> >> +};
> >> +
> >> +module_platform_driver(mlxreg_lc_driver);
> >> +
> >> +MODULE_AUTHOR("Vadim Pasternak <vadimp@xxxxxxxxxx>");
> >> +MODULE_DESCRIPTION("Nvidia line card platform driver");
> >> +MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS("platform:mlxreg-
> lc");
> >>





[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux