Commit 259c8618 authored by Russell King's avatar Russell King Committed by David S. Miller

sfp: add sff module support

Add support for SFF modules, which are soldered down SFP modules.
These have a different phys_id value, and also have the present and
rate select signals omitted compared with their socketed counter-parts.
Signed-off-by: default avatarRussell King <rmk+kernel@armlinux.org.uk>
Reviewed-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 512dc8fe
...@@ -98,12 +98,18 @@ static const enum gpiod_flags gpio_flags[] = { ...@@ -98,12 +98,18 @@ static const enum gpiod_flags gpio_flags[] = {
static DEFINE_MUTEX(sfp_mutex); static DEFINE_MUTEX(sfp_mutex);
struct sff_data {
unsigned int gpios;
bool (*module_supported)(const struct sfp_eeprom_id *id);
};
struct sfp { struct sfp {
struct device *dev; struct device *dev;
struct i2c_adapter *i2c; struct i2c_adapter *i2c;
struct mii_bus *i2c_mii; struct mii_bus *i2c_mii;
struct sfp_bus *sfp_bus; struct sfp_bus *sfp_bus;
struct phy_device *mod_phy; struct phy_device *mod_phy;
const struct sff_data *type;
unsigned int (*get_state)(struct sfp *); unsigned int (*get_state)(struct sfp *);
void (*set_state)(struct sfp *, unsigned int); void (*set_state)(struct sfp *, unsigned int);
...@@ -123,6 +129,36 @@ struct sfp { ...@@ -123,6 +129,36 @@ struct sfp {
struct sfp_eeprom_id id; struct sfp_eeprom_id id;
}; };
static bool sff_module_supported(const struct sfp_eeprom_id *id)
{
return id->base.phys_id == SFP_PHYS_ID_SFF &&
id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP;
}
static const struct sff_data sff_data = {
.gpios = SFP_F_LOS | SFP_F_TX_FAULT | SFP_F_TX_DISABLE,
.module_supported = sff_module_supported,
};
static bool sfp_module_supported(const struct sfp_eeprom_id *id)
{
return id->base.phys_id == SFP_PHYS_ID_SFP &&
id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP;
}
static const struct sff_data sfp_data = {
.gpios = SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT |
SFP_F_TX_DISABLE | SFP_F_RATE_SELECT,
.module_supported = sfp_module_supported,
};
static const struct of_device_id sfp_of_match[] = {
{ .compatible = "sff,sff", .data = &sff_data, },
{ .compatible = "sff,sfp", .data = &sfp_data, },
{ },
};
MODULE_DEVICE_TABLE(of, sfp_of_match);
static unsigned long poll_jiffies; static unsigned long poll_jiffies;
static unsigned int sfp_gpio_get_state(struct sfp *sfp) static unsigned int sfp_gpio_get_state(struct sfp *sfp)
...@@ -141,6 +177,11 @@ static unsigned int sfp_gpio_get_state(struct sfp *sfp) ...@@ -141,6 +177,11 @@ static unsigned int sfp_gpio_get_state(struct sfp *sfp)
return state; return state;
} }
static unsigned int sff_gpio_get_state(struct sfp *sfp)
{
return sfp_gpio_get_state(sfp) | SFP_F_PRESENT;
}
static void sfp_gpio_set_state(struct sfp *sfp, unsigned int state) static void sfp_gpio_set_state(struct sfp *sfp, unsigned int state)
{ {
if (state & SFP_F_PRESENT) { if (state & SFP_F_PRESENT) {
...@@ -479,10 +520,10 @@ static int sfp_sm_mod_probe(struct sfp *sfp) ...@@ -479,10 +520,10 @@ static int sfp_sm_mod_probe(struct sfp *sfp)
dev_info(sfp->dev, "module %s %s rev %s sn %s dc %s\n", dev_info(sfp->dev, "module %s %s rev %s sn %s dc %s\n",
vendor, part, rev, sn, date); vendor, part, rev, sn, date);
/* We only support SFP modules, not the legacy GBIC modules. */ /* Check whether we support this module */
if (sfp->id.base.phys_id != SFP_PHYS_ID_SFP || if (!sfp->type->module_supported(&sfp->id)) {
sfp->id.base.phys_ext_id != SFP_PHYS_EXT_ID_SFP) { dev_err(sfp->dev,
dev_err(sfp->dev, "module is not SFP - phys id 0x%02x 0x%02x\n", "module is not supported - phys id 0x%02x 0x%02x\n",
sfp->id.base.phys_id, sfp->id.base.phys_ext_id); sfp->id.base.phys_id, sfp->id.base.phys_ext_id);
return -EINVAL; return -EINVAL;
} }
...@@ -801,6 +842,7 @@ static void sfp_cleanup(void *data) ...@@ -801,6 +842,7 @@ static void sfp_cleanup(void *data)
static int sfp_probe(struct platform_device *pdev) static int sfp_probe(struct platform_device *pdev)
{ {
const struct sff_data *sff;
struct sfp *sfp; struct sfp *sfp;
bool poll = false; bool poll = false;
int irq, err, i; int irq, err, i;
...@@ -815,10 +857,19 @@ static int sfp_probe(struct platform_device *pdev) ...@@ -815,10 +857,19 @@ static int sfp_probe(struct platform_device *pdev)
if (err < 0) if (err < 0)
return err; return err;
sff = sfp->type = &sfp_data;
if (pdev->dev.of_node) { if (pdev->dev.of_node) {
struct device_node *node = pdev->dev.of_node; struct device_node *node = pdev->dev.of_node;
const struct of_device_id *id;
struct device_node *np; struct device_node *np;
id = of_match_node(sfp_of_match, node);
if (WARN_ON(!id))
return -EINVAL;
sff = sfp->type = id->data;
np = of_parse_phandle(node, "i2c-bus", 0); np = of_parse_phandle(node, "i2c-bus", 0);
if (np) { if (np) {
struct i2c_adapter *i2c; struct i2c_adapter *i2c;
...@@ -834,17 +885,22 @@ static int sfp_probe(struct platform_device *pdev) ...@@ -834,17 +885,22 @@ static int sfp_probe(struct platform_device *pdev)
return err; return err;
} }
} }
}
for (i = 0; i < GPIO_MAX; i++) { for (i = 0; i < GPIO_MAX; i++)
if (sff->gpios & BIT(i)) {
sfp->gpio[i] = devm_gpiod_get_optional(sfp->dev, sfp->gpio[i] = devm_gpiod_get_optional(sfp->dev,
gpio_of_names[i], gpio_flags[i]); gpio_of_names[i], gpio_flags[i]);
if (IS_ERR(sfp->gpio[i])) if (IS_ERR(sfp->gpio[i]))
return PTR_ERR(sfp->gpio[i]); return PTR_ERR(sfp->gpio[i]);
} }
sfp->get_state = sfp_gpio_get_state; sfp->get_state = sfp_gpio_get_state;
sfp->set_state = sfp_gpio_set_state; sfp->set_state = sfp_gpio_set_state;
}
/* Modules that have no detect signal are always present */
if (!(sfp->gpio[GPIO_MODDEF0]))
sfp->get_state = sff_gpio_get_state;
sfp->sfp_bus = sfp_register_socket(sfp->dev, sfp, &sfp_module_ops); sfp->sfp_bus = sfp_register_socket(sfp->dev, sfp, &sfp_module_ops);
if (!sfp->sfp_bus) if (!sfp->sfp_bus)
...@@ -899,12 +955,6 @@ static int sfp_remove(struct platform_device *pdev) ...@@ -899,12 +955,6 @@ static int sfp_remove(struct platform_device *pdev)
return 0; return 0;
} }
static const struct of_device_id sfp_of_match[] = {
{ .compatible = "sff,sfp", },
{ },
};
MODULE_DEVICE_TABLE(of, sfp_of_match);
static struct platform_driver sfp_driver = { static struct platform_driver sfp_driver = {
.probe = sfp_probe, .probe = sfp_probe,
.remove = sfp_remove, .remove = sfp_remove,
......
...@@ -231,6 +231,7 @@ enum { ...@@ -231,6 +231,7 @@ enum {
SFP_SFF8472_COMPLIANCE = 0x5e, SFP_SFF8472_COMPLIANCE = 0x5e,
SFP_CC_EXT = 0x5f, SFP_CC_EXT = 0x5f,
SFP_PHYS_ID_SFF = 0x02,
SFP_PHYS_ID_SFP = 0x03, SFP_PHYS_ID_SFP = 0x03,
SFP_PHYS_EXT_ID_SFP = 0x04, SFP_PHYS_EXT_ID_SFP = 0x04,
SFP_CONNECTOR_UNSPEC = 0x00, SFP_CONNECTOR_UNSPEC = 0x00,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment