Commit f3ac0153 authored by David S. Miller's avatar David S. Miller

Merge branch 'sfp-SFF-module-support'

Russell King says:

====================
Add SFF module support

Add support for SFF modules.  SFF modules are similar to SFP modules,
but they have fewer control signals, and are soldered down rather than
pluggable.

They also have different IDs in the EEPROM to identify as soldered down
SFF modules.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b4cf6a0a 259c8618
...@@ -3,7 +3,9 @@ Transceiver ...@@ -3,7 +3,9 @@ Transceiver
Required properties: Required properties:
- compatible : must be "sff,sfp" - compatible : must be one of
"sff,sfp" for SFP modules
"sff,sff" for soldered down SFF modules
Optional Properties: Optional Properties:
...@@ -11,7 +13,8 @@ Optional Properties: ...@@ -11,7 +13,8 @@ Optional Properties:
interface interface
- mod-def0-gpios : GPIO phandle and a specifier of the MOD-DEF0 (AKA Mod_ABS) - mod-def0-gpios : GPIO phandle and a specifier of the MOD-DEF0 (AKA Mod_ABS)
module presence input gpio signal, active (module absent) high module presence input gpio signal, active (module absent) high. Must
not be present for SFF modules
- los-gpios : GPIO phandle and a specifier of the Receiver Loss of Signal - los-gpios : GPIO phandle and a specifier of the Receiver Loss of Signal
Indication input gpio signal, active (signal lost) high Indication input gpio signal, active (signal lost) high
...@@ -24,10 +27,11 @@ Optional Properties: ...@@ -24,10 +27,11 @@ Optional Properties:
- rate-select0-gpios : GPIO phandle and a specifier of the Rx Signaling Rate - rate-select0-gpios : GPIO phandle and a specifier of the Rx Signaling Rate
Select (AKA RS0) output gpio signal, low: low Rx rate, high: high Rx rate Select (AKA RS0) output gpio signal, low: low Rx rate, high: high Rx rate
Must not be present for SFF modules
- rate-select1-gpios : GPIO phandle and a specifier of the Tx Signaling Rate - rate-select1-gpios : GPIO phandle and a specifier of the Tx Signaling Rate
Select (AKA RS1) output gpio signal (SFP+ only), low: low Tx rate, high: Select (AKA RS1) output gpio signal (SFP+ only), low: low Tx rate, high:
high Tx rate high Tx rate. Must not be present for SFF modules
Example #1: Direct serdes to SFP connection Example #1: Direct serdes to SFP connection
......
...@@ -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