diff options
author | Russell King <rmk+kernel@armlinux.org.uk> | 2017-12-14 05:27:47 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-12-15 13:23:22 -0500 |
commit | 259c8618b0099bfa613997b43857752167cddc20 (patch) | |
tree | 5a9e78ff7b6afd08433d7affa62740e5b88ec84e | |
parent | 512dc8fed99a361e6caf185b14292ab0a60ebd2f (diff) |
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>
-rw-r--r-- | drivers/net/phy/sfp.c | 78 | ||||
-rw-r--r-- | include/linux/sfp.h | 1 |
2 files changed, 65 insertions, 14 deletions
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 9dfc1c4c954f..96511557eb2c 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c | |||
@@ -98,12 +98,18 @@ static const enum gpiod_flags gpio_flags[] = { | |||
98 | 98 | ||
99 | static DEFINE_MUTEX(sfp_mutex); | 99 | static DEFINE_MUTEX(sfp_mutex); |
100 | 100 | ||
101 | struct sff_data { | ||
102 | unsigned int gpios; | ||
103 | bool (*module_supported)(const struct sfp_eeprom_id *id); | ||
104 | }; | ||
105 | |||
101 | struct sfp { | 106 | struct sfp { |
102 | struct device *dev; | 107 | struct device *dev; |
103 | struct i2c_adapter *i2c; | 108 | struct i2c_adapter *i2c; |
104 | struct mii_bus *i2c_mii; | 109 | struct mii_bus *i2c_mii; |
105 | struct sfp_bus *sfp_bus; | 110 | struct sfp_bus *sfp_bus; |
106 | struct phy_device *mod_phy; | 111 | struct phy_device *mod_phy; |
112 | const struct sff_data *type; | ||
107 | 113 | ||
108 | unsigned int (*get_state)(struct sfp *); | 114 | unsigned int (*get_state)(struct sfp *); |
109 | void (*set_state)(struct sfp *, unsigned int); | 115 | void (*set_state)(struct sfp *, unsigned int); |
@@ -123,6 +129,36 @@ struct sfp { | |||
123 | struct sfp_eeprom_id id; | 129 | struct sfp_eeprom_id id; |
124 | }; | 130 | }; |
125 | 131 | ||
132 | static bool sff_module_supported(const struct sfp_eeprom_id *id) | ||
133 | { | ||
134 | return id->base.phys_id == SFP_PHYS_ID_SFF && | ||
135 | id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP; | ||
136 | } | ||
137 | |||
138 | static const struct sff_data sff_data = { | ||
139 | .gpios = SFP_F_LOS | SFP_F_TX_FAULT | SFP_F_TX_DISABLE, | ||
140 | .module_supported = sff_module_supported, | ||
141 | }; | ||
142 | |||
143 | static bool sfp_module_supported(const struct sfp_eeprom_id *id) | ||
144 | { | ||
145 | return id->base.phys_id == SFP_PHYS_ID_SFP && | ||
146 | id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP; | ||
147 | } | ||
148 | |||
149 | static const struct sff_data sfp_data = { | ||
150 | .gpios = SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT | | ||
151 | SFP_F_TX_DISABLE | SFP_F_RATE_SELECT, | ||
152 | .module_supported = sfp_module_supported, | ||
153 | }; | ||
154 | |||
155 | static const struct of_device_id sfp_of_match[] = { | ||
156 | { .compatible = "sff,sff", .data = &sff_data, }, | ||
157 | { .compatible = "sff,sfp", .data = &sfp_data, }, | ||
158 | { }, | ||
159 | }; | ||
160 | MODULE_DEVICE_TABLE(of, sfp_of_match); | ||
161 | |||
126 | static unsigned long poll_jiffies; | 162 | static unsigned long poll_jiffies; |
127 | 163 | ||
128 | static unsigned int sfp_gpio_get_state(struct sfp *sfp) | 164 | 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 | return state; | 177 | return state; |
142 | } | 178 | } |
143 | 179 | ||
180 | static unsigned int sff_gpio_get_state(struct sfp *sfp) | ||
181 | { | ||
182 | return sfp_gpio_get_state(sfp) | SFP_F_PRESENT; | ||
183 | } | ||
184 | |||
144 | static void sfp_gpio_set_state(struct sfp *sfp, unsigned int state) | 185 | static void sfp_gpio_set_state(struct sfp *sfp, unsigned int state) |
145 | { | 186 | { |
146 | if (state & SFP_F_PRESENT) { | 187 | if (state & SFP_F_PRESENT) { |
@@ -479,10 +520,10 @@ static int sfp_sm_mod_probe(struct sfp *sfp) | |||
479 | dev_info(sfp->dev, "module %s %s rev %s sn %s dc %s\n", | 520 | dev_info(sfp->dev, "module %s %s rev %s sn %s dc %s\n", |
480 | vendor, part, rev, sn, date); | 521 | vendor, part, rev, sn, date); |
481 | 522 | ||
482 | /* We only support SFP modules, not the legacy GBIC modules. */ | 523 | /* Check whether we support this module */ |
483 | if (sfp->id.base.phys_id != SFP_PHYS_ID_SFP || | 524 | if (!sfp->type->module_supported(&sfp->id)) { |
484 | sfp->id.base.phys_ext_id != SFP_PHYS_EXT_ID_SFP) { | 525 | dev_err(sfp->dev, |
485 | dev_err(sfp->dev, "module is not SFP - phys id 0x%02x 0x%02x\n", | 526 | "module is not supported - phys id 0x%02x 0x%02x\n", |
486 | sfp->id.base.phys_id, sfp->id.base.phys_ext_id); | 527 | sfp->id.base.phys_id, sfp->id.base.phys_ext_id); |
487 | return -EINVAL; | 528 | return -EINVAL; |
488 | } | 529 | } |
@@ -801,6 +842,7 @@ static void sfp_cleanup(void *data) | |||
801 | 842 | ||
802 | static int sfp_probe(struct platform_device *pdev) | 843 | static int sfp_probe(struct platform_device *pdev) |
803 | { | 844 | { |
845 | const struct sff_data *sff; | ||
804 | struct sfp *sfp; | 846 | struct sfp *sfp; |
805 | bool poll = false; | 847 | bool poll = false; |
806 | int irq, err, i; | 848 | int irq, err, i; |
@@ -815,10 +857,19 @@ static int sfp_probe(struct platform_device *pdev) | |||
815 | if (err < 0) | 857 | if (err < 0) |
816 | return err; | 858 | return err; |
817 | 859 | ||
860 | sff = sfp->type = &sfp_data; | ||
861 | |||
818 | if (pdev->dev.of_node) { | 862 | if (pdev->dev.of_node) { |
819 | struct device_node *node = pdev->dev.of_node; | 863 | struct device_node *node = pdev->dev.of_node; |
864 | const struct of_device_id *id; | ||
820 | struct device_node *np; | 865 | struct device_node *np; |
821 | 866 | ||
867 | id = of_match_node(sfp_of_match, node); | ||
868 | if (WARN_ON(!id)) | ||
869 | return -EINVAL; | ||
870 | |||
871 | sff = sfp->type = id->data; | ||
872 | |||
822 | np = of_parse_phandle(node, "i2c-bus", 0); | 873 | np = of_parse_phandle(node, "i2c-bus", 0); |
823 | if (np) { | 874 | if (np) { |
824 | struct i2c_adapter *i2c; | 875 | struct i2c_adapter *i2c; |
@@ -834,17 +885,22 @@ static int sfp_probe(struct platform_device *pdev) | |||
834 | return err; | 885 | return err; |
835 | } | 886 | } |
836 | } | 887 | } |
888 | } | ||
837 | 889 | ||
838 | for (i = 0; i < GPIO_MAX; i++) { | 890 | for (i = 0; i < GPIO_MAX; i++) |
891 | if (sff->gpios & BIT(i)) { | ||
839 | sfp->gpio[i] = devm_gpiod_get_optional(sfp->dev, | 892 | sfp->gpio[i] = devm_gpiod_get_optional(sfp->dev, |
840 | gpio_of_names[i], gpio_flags[i]); | 893 | gpio_of_names[i], gpio_flags[i]); |
841 | if (IS_ERR(sfp->gpio[i])) | 894 | if (IS_ERR(sfp->gpio[i])) |
842 | return PTR_ERR(sfp->gpio[i]); | 895 | return PTR_ERR(sfp->gpio[i]); |
843 | } | 896 | } |
844 | 897 | ||
845 | sfp->get_state = sfp_gpio_get_state; | 898 | sfp->get_state = sfp_gpio_get_state; |
846 | sfp->set_state = sfp_gpio_set_state; | 899 | sfp->set_state = sfp_gpio_set_state; |
847 | } | 900 | |
901 | /* Modules that have no detect signal are always present */ | ||
902 | if (!(sfp->gpio[GPIO_MODDEF0])) | ||
903 | sfp->get_state = sff_gpio_get_state; | ||
848 | 904 | ||
849 | sfp->sfp_bus = sfp_register_socket(sfp->dev, sfp, &sfp_module_ops); | 905 | sfp->sfp_bus = sfp_register_socket(sfp->dev, sfp, &sfp_module_ops); |
850 | if (!sfp->sfp_bus) | 906 | if (!sfp->sfp_bus) |
@@ -899,12 +955,6 @@ static int sfp_remove(struct platform_device *pdev) | |||
899 | return 0; | 955 | return 0; |
900 | } | 956 | } |
901 | 957 | ||
902 | static const struct of_device_id sfp_of_match[] = { | ||
903 | { .compatible = "sff,sfp", }, | ||
904 | { }, | ||
905 | }; | ||
906 | MODULE_DEVICE_TABLE(of, sfp_of_match); | ||
907 | |||
908 | static struct platform_driver sfp_driver = { | 958 | static struct platform_driver sfp_driver = { |
909 | .probe = sfp_probe, | 959 | .probe = sfp_probe, |
910 | .remove = sfp_remove, | 960 | .remove = sfp_remove, |
diff --git a/include/linux/sfp.h b/include/linux/sfp.h index 47ea32d3e816..0c5c5f6ae1ec 100644 --- a/include/linux/sfp.h +++ b/include/linux/sfp.h | |||
@@ -231,6 +231,7 @@ enum { | |||
231 | SFP_SFF8472_COMPLIANCE = 0x5e, | 231 | SFP_SFF8472_COMPLIANCE = 0x5e, |
232 | SFP_CC_EXT = 0x5f, | 232 | SFP_CC_EXT = 0x5f, |
233 | 233 | ||
234 | SFP_PHYS_ID_SFF = 0x02, | ||
234 | SFP_PHYS_ID_SFP = 0x03, | 235 | SFP_PHYS_ID_SFP = 0x03, |
235 | SFP_PHYS_EXT_ID_SFP = 0x04, | 236 | SFP_PHYS_EXT_ID_SFP = 0x04, |
236 | SFP_CONNECTOR_UNSPEC = 0x00, | 237 | SFP_CONNECTOR_UNSPEC = 0x00, |