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: Russell King <rmk+kernel@armlinux.org.uk> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
512dc8fed9
commit
259c8618b0
+64
-14
@@ -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 {
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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 {
|
|||||||
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,
|
||||||
|
|||||||
Reference in New Issue
Block a user