Skip to content

Commit 33fa690

Browse files
vadimp-nvidiakuba-moo
authored andcommitted
mlxsw: i2c: Add support for system interrupt handling
Extend i2c bus driver with interrupt handler to support system specific hotplug events, related to line card state change. Provide system IRQ line for interrupt handler. IRQ line Id could be provided through the platform data if available, or could be set to the default value. Signed-off-by: Vadim Pasternak <[email protected]> Reviewed-by: Jiri Pirko <[email protected]> Signed-off-by: Ido Schimmel <[email protected]> Signed-off-by: Petr Machata <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 508c29b commit 33fa690

File tree

1 file changed

+86
-1
lines changed
  • drivers/net/ethernet/mellanox/mlxsw

1 file changed

+86
-1
lines changed

drivers/net/ethernet/mellanox/mlxsw/i2c.c

+86-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/mutex.h>
1010
#include <linux/module.h>
1111
#include <linux/mod_devicetable.h>
12+
#include <linux/platform_data/mlxreg.h>
1213
#include <linux/slab.h>
1314

1415
#include "cmd.h"
@@ -51,6 +52,15 @@
5152
#define MLXSW_I2C_TIMEOUT_MSECS 5000
5253
#define MLXSW_I2C_MAX_DATA_SIZE 256
5354

55+
/* Driver can be initialized by kernel platform driver or from the user
56+
* space. In the first case IRQ line number is passed through the platform
57+
* data, otherwise default IRQ line is to be used. Default IRQ is relevant
58+
* only for specific I2C slave address, allowing 3.4 MHz I2C path to the chip
59+
* (special hardware feature for I2C acceleration).
60+
*/
61+
#define MLXSW_I2C_DEFAULT_IRQ 17
62+
#define MLXSW_FAST_I2C_SLAVE 0x37
63+
5464
/**
5565
* struct mlxsw_i2c - device private data:
5666
* @cmd: command attributes;
@@ -63,6 +73,9 @@
6373
* @core: switch core pointer;
6474
* @bus_info: bus info block;
6575
* @block_size: maximum block size allowed to pass to under layer;
76+
* @pdata: device platform data;
77+
* @irq_work: interrupts work item;
78+
* @irq: IRQ line number;
6679
*/
6780
struct mlxsw_i2c {
6881
struct {
@@ -76,6 +89,9 @@ struct mlxsw_i2c {
7689
struct mlxsw_core *core;
7790
struct mlxsw_bus_info bus_info;
7891
u16 block_size;
92+
struct mlxreg_core_hotplug_platform_data *pdata;
93+
struct work_struct irq_work;
94+
int irq;
7995
};
8096

8197
#define MLXSW_I2C_READ_MSG(_client, _addr_buf, _buf, _len) { \
@@ -546,6 +562,67 @@ static void mlxsw_i2c_fini(void *bus_priv)
546562
mlxsw_i2c->core = NULL;
547563
}
548564

565+
static void mlxsw_i2c_work_handler(struct work_struct *work)
566+
{
567+
struct mlxsw_i2c *mlxsw_i2c;
568+
569+
mlxsw_i2c = container_of(work, struct mlxsw_i2c, irq_work);
570+
mlxsw_core_irq_event_handlers_call(mlxsw_i2c->core);
571+
}
572+
573+
static irqreturn_t mlxsw_i2c_irq_handler(int irq, void *dev)
574+
{
575+
struct mlxsw_i2c *mlxsw_i2c = dev;
576+
577+
mlxsw_core_schedule_work(&mlxsw_i2c->irq_work);
578+
579+
/* Interrupt handler shares IRQ line with 'main' interrupt handler.
580+
* Return here IRQ_NONE, while main handler will return IRQ_HANDLED.
581+
*/
582+
return IRQ_NONE;
583+
}
584+
585+
static int mlxsw_i2c_irq_init(struct mlxsw_i2c *mlxsw_i2c, u8 addr)
586+
{
587+
int err;
588+
589+
/* Initialize interrupt handler if system hotplug driver is reachable,
590+
* otherwise interrupt line is not enabled and interrupts will not be
591+
* raised to CPU. Also request_irq() call will be not valid.
592+
*/
593+
if (!IS_REACHABLE(CONFIG_MLXREG_HOTPLUG))
594+
return 0;
595+
596+
/* Set default interrupt line. */
597+
if (mlxsw_i2c->pdata && mlxsw_i2c->pdata->irq)
598+
mlxsw_i2c->irq = mlxsw_i2c->pdata->irq;
599+
else if (addr == MLXSW_FAST_I2C_SLAVE)
600+
mlxsw_i2c->irq = MLXSW_I2C_DEFAULT_IRQ;
601+
602+
if (!mlxsw_i2c->irq)
603+
return 0;
604+
605+
INIT_WORK(&mlxsw_i2c->irq_work, mlxsw_i2c_work_handler);
606+
err = request_irq(mlxsw_i2c->irq, mlxsw_i2c_irq_handler,
607+
IRQF_TRIGGER_FALLING | IRQF_SHARED, "mlxsw-i2c",
608+
mlxsw_i2c);
609+
if (err) {
610+
dev_err(mlxsw_i2c->bus_info.dev, "Failed to request irq: %d\n",
611+
err);
612+
return err;
613+
}
614+
615+
return 0;
616+
}
617+
618+
static void mlxsw_i2c_irq_fini(struct mlxsw_i2c *mlxsw_i2c)
619+
{
620+
if (!IS_REACHABLE(CONFIG_MLXREG_HOTPLUG) || !mlxsw_i2c->irq)
621+
return;
622+
cancel_work_sync(&mlxsw_i2c->irq_work);
623+
free_irq(mlxsw_i2c->irq, mlxsw_i2c);
624+
}
625+
549626
static const struct mlxsw_bus mlxsw_i2c_bus = {
550627
.kind = "i2c",
551628
.init = mlxsw_i2c_init,
@@ -638,17 +715,24 @@ static int mlxsw_i2c_probe(struct i2c_client *client,
638715
mlxsw_i2c->bus_info.dev = &client->dev;
639716
mlxsw_i2c->bus_info.low_frequency = true;
640717
mlxsw_i2c->dev = &client->dev;
718+
mlxsw_i2c->pdata = client->dev.platform_data;
719+
720+
err = mlxsw_i2c_irq_init(mlxsw_i2c, client->addr);
721+
if (err)
722+
goto errout;
641723

642724
err = mlxsw_core_bus_device_register(&mlxsw_i2c->bus_info,
643725
&mlxsw_i2c_bus, mlxsw_i2c, false,
644726
NULL, NULL);
645727
if (err) {
646728
dev_err(&client->dev, "Fail to register core bus\n");
647-
return err;
729+
goto err_bus_device_register;
648730
}
649731

650732
return 0;
651733

734+
err_bus_device_register:
735+
mlxsw_i2c_irq_fini(mlxsw_i2c);
652736
errout:
653737
mutex_destroy(&mlxsw_i2c->cmd.lock);
654738
i2c_set_clientdata(client, NULL);
@@ -661,6 +745,7 @@ static int mlxsw_i2c_remove(struct i2c_client *client)
661745
struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client);
662746

663747
mlxsw_core_bus_device_unregister(mlxsw_i2c->core, false);
748+
mlxsw_i2c_irq_fini(mlxsw_i2c);
664749
mutex_destroy(&mlxsw_i2c->cmd.lock);
665750

666751
return 0;

0 commit comments

Comments
 (0)