162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/debugfs.h>
362306a36Sopenharmony_ci#include <linux/delay.h>
462306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
562306a36Sopenharmony_ci#include <linux/hwmon.h>
662306a36Sopenharmony_ci#include <linux/i2c.h>
762306a36Sopenharmony_ci#include <linux/interrupt.h>
862306a36Sopenharmony_ci#include <linux/jiffies.h>
962306a36Sopenharmony_ci#include <linux/mdio/mdio-i2c.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/mutex.h>
1262306a36Sopenharmony_ci#include <linux/of.h>
1362306a36Sopenharmony_ci#include <linux/phy.h>
1462306a36Sopenharmony_ci#include <linux/platform_device.h>
1562306a36Sopenharmony_ci#include <linux/rtnetlink.h>
1662306a36Sopenharmony_ci#include <linux/slab.h>
1762306a36Sopenharmony_ci#include <linux/workqueue.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "sfp.h"
2062306a36Sopenharmony_ci#include "swphy.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cienum {
2362306a36Sopenharmony_ci	GPIO_MODDEF0,
2462306a36Sopenharmony_ci	GPIO_LOS,
2562306a36Sopenharmony_ci	GPIO_TX_FAULT,
2662306a36Sopenharmony_ci	GPIO_TX_DISABLE,
2762306a36Sopenharmony_ci	GPIO_RS0,
2862306a36Sopenharmony_ci	GPIO_RS1,
2962306a36Sopenharmony_ci	GPIO_MAX,
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	SFP_F_PRESENT = BIT(GPIO_MODDEF0),
3262306a36Sopenharmony_ci	SFP_F_LOS = BIT(GPIO_LOS),
3362306a36Sopenharmony_ci	SFP_F_TX_FAULT = BIT(GPIO_TX_FAULT),
3462306a36Sopenharmony_ci	SFP_F_TX_DISABLE = BIT(GPIO_TX_DISABLE),
3562306a36Sopenharmony_ci	SFP_F_RS0 = BIT(GPIO_RS0),
3662306a36Sopenharmony_ci	SFP_F_RS1 = BIT(GPIO_RS1),
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	SFP_F_OUTPUTS = SFP_F_TX_DISABLE | SFP_F_RS0 | SFP_F_RS1,
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	SFP_E_INSERT = 0,
4162306a36Sopenharmony_ci	SFP_E_REMOVE,
4262306a36Sopenharmony_ci	SFP_E_DEV_ATTACH,
4362306a36Sopenharmony_ci	SFP_E_DEV_DETACH,
4462306a36Sopenharmony_ci	SFP_E_DEV_DOWN,
4562306a36Sopenharmony_ci	SFP_E_DEV_UP,
4662306a36Sopenharmony_ci	SFP_E_TX_FAULT,
4762306a36Sopenharmony_ci	SFP_E_TX_CLEAR,
4862306a36Sopenharmony_ci	SFP_E_LOS_HIGH,
4962306a36Sopenharmony_ci	SFP_E_LOS_LOW,
5062306a36Sopenharmony_ci	SFP_E_TIMEOUT,
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	SFP_MOD_EMPTY = 0,
5362306a36Sopenharmony_ci	SFP_MOD_ERROR,
5462306a36Sopenharmony_ci	SFP_MOD_PROBE,
5562306a36Sopenharmony_ci	SFP_MOD_WAITDEV,
5662306a36Sopenharmony_ci	SFP_MOD_HPOWER,
5762306a36Sopenharmony_ci	SFP_MOD_WAITPWR,
5862306a36Sopenharmony_ci	SFP_MOD_PRESENT,
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	SFP_DEV_DETACHED = 0,
6162306a36Sopenharmony_ci	SFP_DEV_DOWN,
6262306a36Sopenharmony_ci	SFP_DEV_UP,
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	SFP_S_DOWN = 0,
6562306a36Sopenharmony_ci	SFP_S_FAIL,
6662306a36Sopenharmony_ci	SFP_S_WAIT,
6762306a36Sopenharmony_ci	SFP_S_INIT,
6862306a36Sopenharmony_ci	SFP_S_INIT_PHY,
6962306a36Sopenharmony_ci	SFP_S_INIT_TX_FAULT,
7062306a36Sopenharmony_ci	SFP_S_WAIT_LOS,
7162306a36Sopenharmony_ci	SFP_S_LINK_UP,
7262306a36Sopenharmony_ci	SFP_S_TX_FAULT,
7362306a36Sopenharmony_ci	SFP_S_REINIT,
7462306a36Sopenharmony_ci	SFP_S_TX_DISABLE,
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic const char  * const mod_state_strings[] = {
7862306a36Sopenharmony_ci	[SFP_MOD_EMPTY] = "empty",
7962306a36Sopenharmony_ci	[SFP_MOD_ERROR] = "error",
8062306a36Sopenharmony_ci	[SFP_MOD_PROBE] = "probe",
8162306a36Sopenharmony_ci	[SFP_MOD_WAITDEV] = "waitdev",
8262306a36Sopenharmony_ci	[SFP_MOD_HPOWER] = "hpower",
8362306a36Sopenharmony_ci	[SFP_MOD_WAITPWR] = "waitpwr",
8462306a36Sopenharmony_ci	[SFP_MOD_PRESENT] = "present",
8562306a36Sopenharmony_ci};
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic const char *mod_state_to_str(unsigned short mod_state)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	if (mod_state >= ARRAY_SIZE(mod_state_strings))
9062306a36Sopenharmony_ci		return "Unknown module state";
9162306a36Sopenharmony_ci	return mod_state_strings[mod_state];
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic const char * const dev_state_strings[] = {
9562306a36Sopenharmony_ci	[SFP_DEV_DETACHED] = "detached",
9662306a36Sopenharmony_ci	[SFP_DEV_DOWN] = "down",
9762306a36Sopenharmony_ci	[SFP_DEV_UP] = "up",
9862306a36Sopenharmony_ci};
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic const char *dev_state_to_str(unsigned short dev_state)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	if (dev_state >= ARRAY_SIZE(dev_state_strings))
10362306a36Sopenharmony_ci		return "Unknown device state";
10462306a36Sopenharmony_ci	return dev_state_strings[dev_state];
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic const char * const event_strings[] = {
10862306a36Sopenharmony_ci	[SFP_E_INSERT] = "insert",
10962306a36Sopenharmony_ci	[SFP_E_REMOVE] = "remove",
11062306a36Sopenharmony_ci	[SFP_E_DEV_ATTACH] = "dev_attach",
11162306a36Sopenharmony_ci	[SFP_E_DEV_DETACH] = "dev_detach",
11262306a36Sopenharmony_ci	[SFP_E_DEV_DOWN] = "dev_down",
11362306a36Sopenharmony_ci	[SFP_E_DEV_UP] = "dev_up",
11462306a36Sopenharmony_ci	[SFP_E_TX_FAULT] = "tx_fault",
11562306a36Sopenharmony_ci	[SFP_E_TX_CLEAR] = "tx_clear",
11662306a36Sopenharmony_ci	[SFP_E_LOS_HIGH] = "los_high",
11762306a36Sopenharmony_ci	[SFP_E_LOS_LOW] = "los_low",
11862306a36Sopenharmony_ci	[SFP_E_TIMEOUT] = "timeout",
11962306a36Sopenharmony_ci};
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic const char *event_to_str(unsigned short event)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	if (event >= ARRAY_SIZE(event_strings))
12462306a36Sopenharmony_ci		return "Unknown event";
12562306a36Sopenharmony_ci	return event_strings[event];
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic const char * const sm_state_strings[] = {
12962306a36Sopenharmony_ci	[SFP_S_DOWN] = "down",
13062306a36Sopenharmony_ci	[SFP_S_FAIL] = "fail",
13162306a36Sopenharmony_ci	[SFP_S_WAIT] = "wait",
13262306a36Sopenharmony_ci	[SFP_S_INIT] = "init",
13362306a36Sopenharmony_ci	[SFP_S_INIT_PHY] = "init_phy",
13462306a36Sopenharmony_ci	[SFP_S_INIT_TX_FAULT] = "init_tx_fault",
13562306a36Sopenharmony_ci	[SFP_S_WAIT_LOS] = "wait_los",
13662306a36Sopenharmony_ci	[SFP_S_LINK_UP] = "link_up",
13762306a36Sopenharmony_ci	[SFP_S_TX_FAULT] = "tx_fault",
13862306a36Sopenharmony_ci	[SFP_S_REINIT] = "reinit",
13962306a36Sopenharmony_ci	[SFP_S_TX_DISABLE] = "tx_disable",
14062306a36Sopenharmony_ci};
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic const char *sm_state_to_str(unsigned short sm_state)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	if (sm_state >= ARRAY_SIZE(sm_state_strings))
14562306a36Sopenharmony_ci		return "Unknown state";
14662306a36Sopenharmony_ci	return sm_state_strings[sm_state];
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic const char *gpio_names[] = {
15062306a36Sopenharmony_ci	"mod-def0",
15162306a36Sopenharmony_ci	"los",
15262306a36Sopenharmony_ci	"tx-fault",
15362306a36Sopenharmony_ci	"tx-disable",
15462306a36Sopenharmony_ci	"rate-select0",
15562306a36Sopenharmony_ci	"rate-select1",
15662306a36Sopenharmony_ci};
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic const enum gpiod_flags gpio_flags[] = {
15962306a36Sopenharmony_ci	GPIOD_IN,
16062306a36Sopenharmony_ci	GPIOD_IN,
16162306a36Sopenharmony_ci	GPIOD_IN,
16262306a36Sopenharmony_ci	GPIOD_ASIS,
16362306a36Sopenharmony_ci	GPIOD_ASIS,
16462306a36Sopenharmony_ci	GPIOD_ASIS,
16562306a36Sopenharmony_ci};
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci/* t_start_up (SFF-8431) or t_init (SFF-8472) is the time required for a
16862306a36Sopenharmony_ci * non-cooled module to initialise its laser safety circuitry. We wait
16962306a36Sopenharmony_ci * an initial T_WAIT period before we check the tx fault to give any PHY
17062306a36Sopenharmony_ci * on board (for a copper SFP) time to initialise.
17162306a36Sopenharmony_ci */
17262306a36Sopenharmony_ci#define T_WAIT			msecs_to_jiffies(50)
17362306a36Sopenharmony_ci#define T_START_UP		msecs_to_jiffies(300)
17462306a36Sopenharmony_ci#define T_START_UP_BAD_GPON	msecs_to_jiffies(60000)
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci/* t_reset is the time required to assert the TX_DISABLE signal to reset
17762306a36Sopenharmony_ci * an indicated TX_FAULT.
17862306a36Sopenharmony_ci */
17962306a36Sopenharmony_ci#define T_RESET_US		10
18062306a36Sopenharmony_ci#define T_FAULT_RECOVER		msecs_to_jiffies(1000)
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci/* N_FAULT_INIT is the number of recovery attempts at module initialisation
18362306a36Sopenharmony_ci * time. If the TX_FAULT signal is not deasserted after this number of
18462306a36Sopenharmony_ci * attempts at clearing it, we decide that the module is faulty.
18562306a36Sopenharmony_ci * N_FAULT is the same but after the module has initialised.
18662306a36Sopenharmony_ci */
18762306a36Sopenharmony_ci#define N_FAULT_INIT		5
18862306a36Sopenharmony_ci#define N_FAULT			5
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci/* T_PHY_RETRY is the time interval between attempts to probe the PHY.
19162306a36Sopenharmony_ci * R_PHY_RETRY is the number of attempts.
19262306a36Sopenharmony_ci */
19362306a36Sopenharmony_ci#define T_PHY_RETRY		msecs_to_jiffies(50)
19462306a36Sopenharmony_ci#define R_PHY_RETRY		12
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci/* SFP module presence detection is poor: the three MOD DEF signals are
19762306a36Sopenharmony_ci * the same length on the PCB, which means it's possible for MOD DEF 0 to
19862306a36Sopenharmony_ci * connect before the I2C bus on MOD DEF 1/2.
19962306a36Sopenharmony_ci *
20062306a36Sopenharmony_ci * The SFF-8472 specifies t_serial ("Time from power on until module is
20162306a36Sopenharmony_ci * ready for data transmission over the two wire serial bus.") as 300ms.
20262306a36Sopenharmony_ci */
20362306a36Sopenharmony_ci#define T_SERIAL		msecs_to_jiffies(300)
20462306a36Sopenharmony_ci#define T_HPOWER_LEVEL		msecs_to_jiffies(300)
20562306a36Sopenharmony_ci#define T_PROBE_RETRY_INIT	msecs_to_jiffies(100)
20662306a36Sopenharmony_ci#define R_PROBE_RETRY_INIT	10
20762306a36Sopenharmony_ci#define T_PROBE_RETRY_SLOW	msecs_to_jiffies(5000)
20862306a36Sopenharmony_ci#define R_PROBE_RETRY_SLOW	12
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci/* SFP modules appear to always have their PHY configured for bus address
21162306a36Sopenharmony_ci * 0x56 (which with mdio-i2c, translates to a PHY address of 22).
21262306a36Sopenharmony_ci * RollBall SFPs access phy via SFP Enhanced Digital Diagnostic Interface
21362306a36Sopenharmony_ci * via address 0x51 (mdio-i2c will use RollBall protocol on this address).
21462306a36Sopenharmony_ci */
21562306a36Sopenharmony_ci#define SFP_PHY_ADDR		22
21662306a36Sopenharmony_ci#define SFP_PHY_ADDR_ROLLBALL	17
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci/* SFP_EEPROM_BLOCK_SIZE is the size of data chunk to read the EEPROM
21962306a36Sopenharmony_ci * at a time. Some SFP modules and also some Linux I2C drivers do not like
22062306a36Sopenharmony_ci * reads longer than 16 bytes.
22162306a36Sopenharmony_ci */
22262306a36Sopenharmony_ci#define SFP_EEPROM_BLOCK_SIZE	16
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistruct sff_data {
22562306a36Sopenharmony_ci	unsigned int gpios;
22662306a36Sopenharmony_ci	bool (*module_supported)(const struct sfp_eeprom_id *id);
22762306a36Sopenharmony_ci};
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistruct sfp {
23062306a36Sopenharmony_ci	struct device *dev;
23162306a36Sopenharmony_ci	struct i2c_adapter *i2c;
23262306a36Sopenharmony_ci	struct mii_bus *i2c_mii;
23362306a36Sopenharmony_ci	struct sfp_bus *sfp_bus;
23462306a36Sopenharmony_ci	enum mdio_i2c_proto mdio_protocol;
23562306a36Sopenharmony_ci	struct phy_device *mod_phy;
23662306a36Sopenharmony_ci	const struct sff_data *type;
23762306a36Sopenharmony_ci	size_t i2c_block_size;
23862306a36Sopenharmony_ci	u32 max_power_mW;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	unsigned int (*get_state)(struct sfp *);
24162306a36Sopenharmony_ci	void (*set_state)(struct sfp *, unsigned int);
24262306a36Sopenharmony_ci	int (*read)(struct sfp *, bool, u8, void *, size_t);
24362306a36Sopenharmony_ci	int (*write)(struct sfp *, bool, u8, void *, size_t);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	struct gpio_desc *gpio[GPIO_MAX];
24662306a36Sopenharmony_ci	int gpio_irq[GPIO_MAX];
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	bool need_poll;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	/* Access rules:
25162306a36Sopenharmony_ci	 * state_hw_drive: st_mutex held
25262306a36Sopenharmony_ci	 * state_hw_mask: st_mutex held
25362306a36Sopenharmony_ci	 * state_soft_mask: st_mutex held
25462306a36Sopenharmony_ci	 * state: st_mutex held unless reading input bits
25562306a36Sopenharmony_ci	 */
25662306a36Sopenharmony_ci	struct mutex st_mutex;			/* Protects state */
25762306a36Sopenharmony_ci	unsigned int state_hw_drive;
25862306a36Sopenharmony_ci	unsigned int state_hw_mask;
25962306a36Sopenharmony_ci	unsigned int state_soft_mask;
26062306a36Sopenharmony_ci	unsigned int state;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	struct delayed_work poll;
26362306a36Sopenharmony_ci	struct delayed_work timeout;
26462306a36Sopenharmony_ci	struct mutex sm_mutex;			/* Protects state machine */
26562306a36Sopenharmony_ci	unsigned char sm_mod_state;
26662306a36Sopenharmony_ci	unsigned char sm_mod_tries_init;
26762306a36Sopenharmony_ci	unsigned char sm_mod_tries;
26862306a36Sopenharmony_ci	unsigned char sm_dev_state;
26962306a36Sopenharmony_ci	unsigned short sm_state;
27062306a36Sopenharmony_ci	unsigned char sm_fault_retries;
27162306a36Sopenharmony_ci	unsigned char sm_phy_retries;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	struct sfp_eeprom_id id;
27462306a36Sopenharmony_ci	unsigned int module_power_mW;
27562306a36Sopenharmony_ci	unsigned int module_t_start_up;
27662306a36Sopenharmony_ci	unsigned int module_t_wait;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	unsigned int rate_kbd;
27962306a36Sopenharmony_ci	unsigned int rs_threshold_kbd;
28062306a36Sopenharmony_ci	unsigned int rs_state_mask;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	bool have_a2;
28362306a36Sopenharmony_ci	bool tx_fault_ignore;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	const struct sfp_quirk *quirk;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_HWMON)
28862306a36Sopenharmony_ci	struct sfp_diag diag;
28962306a36Sopenharmony_ci	struct delayed_work hwmon_probe;
29062306a36Sopenharmony_ci	unsigned int hwmon_tries;
29162306a36Sopenharmony_ci	struct device *hwmon_dev;
29262306a36Sopenharmony_ci	char *hwmon_name;
29362306a36Sopenharmony_ci#endif
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DEBUG_FS)
29662306a36Sopenharmony_ci	struct dentry *debugfs_dir;
29762306a36Sopenharmony_ci#endif
29862306a36Sopenharmony_ci};
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic bool sff_module_supported(const struct sfp_eeprom_id *id)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	return id->base.phys_id == SFF8024_ID_SFF_8472 &&
30362306a36Sopenharmony_ci	       id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP;
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic const struct sff_data sff_data = {
30762306a36Sopenharmony_ci	.gpios = SFP_F_LOS | SFP_F_TX_FAULT | SFP_F_TX_DISABLE,
30862306a36Sopenharmony_ci	.module_supported = sff_module_supported,
30962306a36Sopenharmony_ci};
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic bool sfp_module_supported(const struct sfp_eeprom_id *id)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	if (id->base.phys_id == SFF8024_ID_SFP &&
31462306a36Sopenharmony_ci	    id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP)
31562306a36Sopenharmony_ci		return true;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	/* SFP GPON module Ubiquiti U-Fiber Instant has in its EEPROM stored
31862306a36Sopenharmony_ci	 * phys id SFF instead of SFP. Therefore mark this module explicitly
31962306a36Sopenharmony_ci	 * as supported based on vendor name and pn match.
32062306a36Sopenharmony_ci	 */
32162306a36Sopenharmony_ci	if (id->base.phys_id == SFF8024_ID_SFF_8472 &&
32262306a36Sopenharmony_ci	    id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP &&
32362306a36Sopenharmony_ci	    !memcmp(id->base.vendor_name, "UBNT            ", 16) &&
32462306a36Sopenharmony_ci	    !memcmp(id->base.vendor_pn, "UF-INSTANT      ", 16))
32562306a36Sopenharmony_ci		return true;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	return false;
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic const struct sff_data sfp_data = {
33162306a36Sopenharmony_ci	.gpios = SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT |
33262306a36Sopenharmony_ci		 SFP_F_TX_DISABLE | SFP_F_RS0 | SFP_F_RS1,
33362306a36Sopenharmony_ci	.module_supported = sfp_module_supported,
33462306a36Sopenharmony_ci};
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic const struct of_device_id sfp_of_match[] = {
33762306a36Sopenharmony_ci	{ .compatible = "sff,sff", .data = &sff_data, },
33862306a36Sopenharmony_ci	{ .compatible = "sff,sfp", .data = &sfp_data, },
33962306a36Sopenharmony_ci	{ },
34062306a36Sopenharmony_ci};
34162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sfp_of_match);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic void sfp_fixup_long_startup(struct sfp *sfp)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	sfp->module_t_start_up = T_START_UP_BAD_GPON;
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_cistatic void sfp_fixup_ignore_tx_fault(struct sfp *sfp)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	sfp->tx_fault_ignore = true;
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci// For 10GBASE-T short-reach modules
35462306a36Sopenharmony_cistatic void sfp_fixup_10gbaset_30m(struct sfp *sfp)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	sfp->id.base.connector = SFF8024_CONNECTOR_RJ45;
35762306a36Sopenharmony_ci	sfp->id.base.extended_cc = SFF8024_ECC_10GBASE_T_SR;
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistatic void sfp_fixup_rollball_proto(struct sfp *sfp, unsigned int secs)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	sfp->mdio_protocol = MDIO_I2C_ROLLBALL;
36362306a36Sopenharmony_ci	sfp->module_t_wait = msecs_to_jiffies(secs * 1000);
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic void sfp_fixup_fs_10gt(struct sfp *sfp)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	sfp_fixup_10gbaset_30m(sfp);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	// These SFPs need 4 seconds before the PHY can be accessed
37162306a36Sopenharmony_ci	sfp_fixup_rollball_proto(sfp, 4);
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_cistatic void sfp_fixup_halny_gsfp(struct sfp *sfp)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	/* Ignore the TX_FAULT and LOS signals on this module.
37762306a36Sopenharmony_ci	 * these are possibly used for other purposes on this
37862306a36Sopenharmony_ci	 * module, e.g. a serial port.
37962306a36Sopenharmony_ci	 */
38062306a36Sopenharmony_ci	sfp->state_hw_mask &= ~(SFP_F_TX_FAULT | SFP_F_LOS);
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic void sfp_fixup_rollball(struct sfp *sfp)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	// Rollball SFPs need 25 seconds before the PHY can be accessed
38662306a36Sopenharmony_ci	sfp_fixup_rollball_proto(sfp, 25);
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic void sfp_fixup_rollball_cc(struct sfp *sfp)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	sfp_fixup_rollball(sfp);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	/* Some RollBall SFPs may have wrong (zero) extended compliance code
39462306a36Sopenharmony_ci	 * burned in EEPROM. For PHY probing we need the correct one.
39562306a36Sopenharmony_ci	 */
39662306a36Sopenharmony_ci	sfp->id.base.extended_cc = SFF8024_ECC_10GBASE_T_SFI;
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_cistatic void sfp_quirk_2500basex(const struct sfp_eeprom_id *id,
40062306a36Sopenharmony_ci				unsigned long *modes,
40162306a36Sopenharmony_ci				unsigned long *interfaces)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, modes);
40462306a36Sopenharmony_ci	__set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces);
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic void sfp_quirk_disable_autoneg(const struct sfp_eeprom_id *id,
40862306a36Sopenharmony_ci				      unsigned long *modes,
40962306a36Sopenharmony_ci				      unsigned long *interfaces)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, modes);
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic void sfp_quirk_oem_2_5g(const struct sfp_eeprom_id *id,
41562306a36Sopenharmony_ci			       unsigned long *modes,
41662306a36Sopenharmony_ci			       unsigned long *interfaces)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	/* Copper 2.5G SFP */
41962306a36Sopenharmony_ci	linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, modes);
42062306a36Sopenharmony_ci	__set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces);
42162306a36Sopenharmony_ci	sfp_quirk_disable_autoneg(id, modes, interfaces);
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id,
42562306a36Sopenharmony_ci				      unsigned long *modes,
42662306a36Sopenharmony_ci				      unsigned long *interfaces)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	/* Ubiquiti U-Fiber Instant module claims that support all transceiver
42962306a36Sopenharmony_ci	 * types including 10G Ethernet which is not truth. So clear all claimed
43062306a36Sopenharmony_ci	 * modes and set only one mode which module supports: 1000baseX_Full.
43162306a36Sopenharmony_ci	 */
43262306a36Sopenharmony_ci	linkmode_zero(modes);
43362306a36Sopenharmony_ci	linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, modes);
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci#define SFP_QUIRK(_v, _p, _m, _f) \
43762306a36Sopenharmony_ci	{ .vendor = _v, .part = _p, .modes = _m, .fixup = _f, }
43862306a36Sopenharmony_ci#define SFP_QUIRK_M(_v, _p, _m) SFP_QUIRK(_v, _p, _m, NULL)
43962306a36Sopenharmony_ci#define SFP_QUIRK_F(_v, _p, _f) SFP_QUIRK(_v, _p, NULL, _f)
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic const struct sfp_quirk sfp_quirks[] = {
44262306a36Sopenharmony_ci	// Alcatel Lucent G-010S-P can operate at 2500base-X, but incorrectly
44362306a36Sopenharmony_ci	// report 2500MBd NRZ in their EEPROM
44462306a36Sopenharmony_ci	SFP_QUIRK_M("ALCATELLUCENT", "G010SP", sfp_quirk_2500basex),
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	// Alcatel Lucent G-010S-A can operate at 2500base-X, but report 3.2GBd
44762306a36Sopenharmony_ci	// NRZ in their EEPROM
44862306a36Sopenharmony_ci	SFP_QUIRK("ALCATELLUCENT", "3FE46541AA", sfp_quirk_2500basex,
44962306a36Sopenharmony_ci		  sfp_fixup_long_startup),
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	// Fiberstore SFP-10G-T doesn't identify as copper, and uses the
45262306a36Sopenharmony_ci	// Rollball protocol to talk to the PHY.
45362306a36Sopenharmony_ci	SFP_QUIRK_F("FS", "SFP-10G-T", sfp_fixup_fs_10gt),
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	// Fiberstore GPON-ONU-34-20BI can operate at 2500base-X, but report 1.2GBd
45662306a36Sopenharmony_ci	// NRZ in their EEPROM
45762306a36Sopenharmony_ci	SFP_QUIRK("FS", "GPON-ONU-34-20BI", sfp_quirk_2500basex,
45862306a36Sopenharmony_ci		  sfp_fixup_ignore_tx_fault),
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	SFP_QUIRK_F("HALNy", "HL-GSFP", sfp_fixup_halny_gsfp),
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	// HG MXPD-483II-F 2.5G supports 2500Base-X, but incorrectly reports
46362306a36Sopenharmony_ci	// 2600MBd in their EERPOM
46462306a36Sopenharmony_ci	SFP_QUIRK_M("HG GENUINE", "MXPD-483II", sfp_quirk_2500basex),
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	// Huawei MA5671A can operate at 2500base-X, but report 1.2GBd NRZ in
46762306a36Sopenharmony_ci	// their EEPROM
46862306a36Sopenharmony_ci	SFP_QUIRK("HUAWEI", "MA5671A", sfp_quirk_2500basex,
46962306a36Sopenharmony_ci		  sfp_fixup_ignore_tx_fault),
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	// FS 2.5G Base-T
47262306a36Sopenharmony_ci	SFP_QUIRK_M("FS", "SFP-2.5G-T", sfp_quirk_oem_2_5g),
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	// Lantech 8330-262D-E can operate at 2500base-X, but incorrectly report
47562306a36Sopenharmony_ci	// 2500MBd NRZ in their EEPROM
47662306a36Sopenharmony_ci	SFP_QUIRK_M("Lantech", "8330-262D-E", sfp_quirk_2500basex),
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	SFP_QUIRK_M("UBNT", "UF-INSTANT", sfp_quirk_ubnt_uf_instant),
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	// Walsun HXSX-ATR[CI]-1 don't identify as copper, and use the
48162306a36Sopenharmony_ci	// Rollball protocol to talk to the PHY.
48262306a36Sopenharmony_ci	SFP_QUIRK_F("Walsun", "HXSX-ATRC-1", sfp_fixup_fs_10gt),
48362306a36Sopenharmony_ci	SFP_QUIRK_F("Walsun", "HXSX-ATRI-1", sfp_fixup_fs_10gt),
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc),
48662306a36Sopenharmony_ci	SFP_QUIRK_M("OEM", "SFP-2.5G-T", sfp_quirk_oem_2_5g),
48762306a36Sopenharmony_ci	SFP_QUIRK_F("OEM", "RTSFP-10", sfp_fixup_rollball_cc),
48862306a36Sopenharmony_ci	SFP_QUIRK_F("OEM", "RTSFP-10G", sfp_fixup_rollball_cc),
48962306a36Sopenharmony_ci	SFP_QUIRK_F("Turris", "RTSFP-10", sfp_fixup_rollball),
49062306a36Sopenharmony_ci	SFP_QUIRK_F("Turris", "RTSFP-10G", sfp_fixup_rollball),
49162306a36Sopenharmony_ci};
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic size_t sfp_strlen(const char *str, size_t maxlen)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	size_t size, i;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	/* Trailing characters should be filled with space chars, but
49862306a36Sopenharmony_ci	 * some manufacturers can't read SFF-8472 and use NUL.
49962306a36Sopenharmony_ci	 */
50062306a36Sopenharmony_ci	for (i = 0, size = 0; i < maxlen; i++)
50162306a36Sopenharmony_ci		if (str[i] != ' ' && str[i] != '\0')
50262306a36Sopenharmony_ci			size = i + 1;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	return size;
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_cistatic bool sfp_match(const char *qs, const char *str, size_t len)
50862306a36Sopenharmony_ci{
50962306a36Sopenharmony_ci	if (!qs)
51062306a36Sopenharmony_ci		return true;
51162306a36Sopenharmony_ci	if (strlen(qs) != len)
51262306a36Sopenharmony_ci		return false;
51362306a36Sopenharmony_ci	return !strncmp(qs, str, len);
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cistatic const struct sfp_quirk *sfp_lookup_quirk(const struct sfp_eeprom_id *id)
51762306a36Sopenharmony_ci{
51862306a36Sopenharmony_ci	const struct sfp_quirk *q;
51962306a36Sopenharmony_ci	unsigned int i;
52062306a36Sopenharmony_ci	size_t vs, ps;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	vs = sfp_strlen(id->base.vendor_name, ARRAY_SIZE(id->base.vendor_name));
52362306a36Sopenharmony_ci	ps = sfp_strlen(id->base.vendor_pn, ARRAY_SIZE(id->base.vendor_pn));
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	for (i = 0, q = sfp_quirks; i < ARRAY_SIZE(sfp_quirks); i++, q++)
52662306a36Sopenharmony_ci		if (sfp_match(q->vendor, id->base.vendor_name, vs) &&
52762306a36Sopenharmony_ci		    sfp_match(q->part, id->base.vendor_pn, ps))
52862306a36Sopenharmony_ci			return q;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	return NULL;
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic unsigned long poll_jiffies;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_cistatic unsigned int sfp_gpio_get_state(struct sfp *sfp)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	unsigned int i, state, v;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	for (i = state = 0; i < GPIO_MAX; i++) {
54062306a36Sopenharmony_ci		if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i])
54162306a36Sopenharmony_ci			continue;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci		v = gpiod_get_value_cansleep(sfp->gpio[i]);
54462306a36Sopenharmony_ci		if (v)
54562306a36Sopenharmony_ci			state |= BIT(i);
54662306a36Sopenharmony_ci	}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	return state;
54962306a36Sopenharmony_ci}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_cistatic unsigned int sff_gpio_get_state(struct sfp *sfp)
55262306a36Sopenharmony_ci{
55362306a36Sopenharmony_ci	return sfp_gpio_get_state(sfp) | SFP_F_PRESENT;
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistatic void sfp_gpio_set_state(struct sfp *sfp, unsigned int state)
55762306a36Sopenharmony_ci{
55862306a36Sopenharmony_ci	unsigned int drive;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	if (state & SFP_F_PRESENT)
56162306a36Sopenharmony_ci		/* If the module is present, drive the requested signals */
56262306a36Sopenharmony_ci		drive = sfp->state_hw_drive;
56362306a36Sopenharmony_ci	else
56462306a36Sopenharmony_ci		/* Otherwise, let them float to the pull-ups */
56562306a36Sopenharmony_ci		drive = 0;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	if (sfp->gpio[GPIO_TX_DISABLE]) {
56862306a36Sopenharmony_ci		if (drive & SFP_F_TX_DISABLE)
56962306a36Sopenharmony_ci			gpiod_direction_output(sfp->gpio[GPIO_TX_DISABLE],
57062306a36Sopenharmony_ci					       state & SFP_F_TX_DISABLE);
57162306a36Sopenharmony_ci		else
57262306a36Sopenharmony_ci			gpiod_direction_input(sfp->gpio[GPIO_TX_DISABLE]);
57362306a36Sopenharmony_ci	}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	if (sfp->gpio[GPIO_RS0]) {
57662306a36Sopenharmony_ci		if (drive & SFP_F_RS0)
57762306a36Sopenharmony_ci			gpiod_direction_output(sfp->gpio[GPIO_RS0],
57862306a36Sopenharmony_ci					       state & SFP_F_RS0);
57962306a36Sopenharmony_ci		else
58062306a36Sopenharmony_ci			gpiod_direction_input(sfp->gpio[GPIO_RS0]);
58162306a36Sopenharmony_ci	}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	if (sfp->gpio[GPIO_RS1]) {
58462306a36Sopenharmony_ci		if (drive & SFP_F_RS1)
58562306a36Sopenharmony_ci			gpiod_direction_output(sfp->gpio[GPIO_RS1],
58662306a36Sopenharmony_ci					       state & SFP_F_RS1);
58762306a36Sopenharmony_ci		else
58862306a36Sopenharmony_ci			gpiod_direction_input(sfp->gpio[GPIO_RS1]);
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_cistatic int sfp_i2c_read(struct sfp *sfp, bool a2, u8 dev_addr, void *buf,
59362306a36Sopenharmony_ci			size_t len)
59462306a36Sopenharmony_ci{
59562306a36Sopenharmony_ci	struct i2c_msg msgs[2];
59662306a36Sopenharmony_ci	u8 bus_addr = a2 ? 0x51 : 0x50;
59762306a36Sopenharmony_ci	size_t block_size = sfp->i2c_block_size;
59862306a36Sopenharmony_ci	size_t this_len;
59962306a36Sopenharmony_ci	int ret;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	msgs[0].addr = bus_addr;
60262306a36Sopenharmony_ci	msgs[0].flags = 0;
60362306a36Sopenharmony_ci	msgs[0].len = 1;
60462306a36Sopenharmony_ci	msgs[0].buf = &dev_addr;
60562306a36Sopenharmony_ci	msgs[1].addr = bus_addr;
60662306a36Sopenharmony_ci	msgs[1].flags = I2C_M_RD;
60762306a36Sopenharmony_ci	msgs[1].len = len;
60862306a36Sopenharmony_ci	msgs[1].buf = buf;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	while (len) {
61162306a36Sopenharmony_ci		this_len = len;
61262306a36Sopenharmony_ci		if (this_len > block_size)
61362306a36Sopenharmony_ci			this_len = block_size;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci		msgs[1].len = this_len;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci		ret = i2c_transfer(sfp->i2c, msgs, ARRAY_SIZE(msgs));
61862306a36Sopenharmony_ci		if (ret < 0)
61962306a36Sopenharmony_ci			return ret;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci		if (ret != ARRAY_SIZE(msgs))
62262306a36Sopenharmony_ci			break;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci		msgs[1].buf += this_len;
62562306a36Sopenharmony_ci		dev_addr += this_len;
62662306a36Sopenharmony_ci		len -= this_len;
62762306a36Sopenharmony_ci	}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	return msgs[1].buf - (u8 *)buf;
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_cistatic int sfp_i2c_write(struct sfp *sfp, bool a2, u8 dev_addr, void *buf,
63362306a36Sopenharmony_ci	size_t len)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	struct i2c_msg msgs[1];
63662306a36Sopenharmony_ci	u8 bus_addr = a2 ? 0x51 : 0x50;
63762306a36Sopenharmony_ci	int ret;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	msgs[0].addr = bus_addr;
64062306a36Sopenharmony_ci	msgs[0].flags = 0;
64162306a36Sopenharmony_ci	msgs[0].len = 1 + len;
64262306a36Sopenharmony_ci	msgs[0].buf = kmalloc(1 + len, GFP_KERNEL);
64362306a36Sopenharmony_ci	if (!msgs[0].buf)
64462306a36Sopenharmony_ci		return -ENOMEM;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	msgs[0].buf[0] = dev_addr;
64762306a36Sopenharmony_ci	memcpy(&msgs[0].buf[1], buf, len);
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	ret = i2c_transfer(sfp->i2c, msgs, ARRAY_SIZE(msgs));
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	kfree(msgs[0].buf);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	if (ret < 0)
65462306a36Sopenharmony_ci		return ret;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	return ret == ARRAY_SIZE(msgs) ? len : 0;
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_cistatic int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
66062306a36Sopenharmony_ci{
66162306a36Sopenharmony_ci	if (!i2c_check_functionality(i2c, I2C_FUNC_I2C))
66262306a36Sopenharmony_ci		return -EINVAL;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	sfp->i2c = i2c;
66562306a36Sopenharmony_ci	sfp->read = sfp_i2c_read;
66662306a36Sopenharmony_ci	sfp->write = sfp_i2c_write;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	return 0;
66962306a36Sopenharmony_ci}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_cistatic int sfp_i2c_mdiobus_create(struct sfp *sfp)
67262306a36Sopenharmony_ci{
67362306a36Sopenharmony_ci	struct mii_bus *i2c_mii;
67462306a36Sopenharmony_ci	int ret;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	i2c_mii = mdio_i2c_alloc(sfp->dev, sfp->i2c, sfp->mdio_protocol);
67762306a36Sopenharmony_ci	if (IS_ERR(i2c_mii))
67862306a36Sopenharmony_ci		return PTR_ERR(i2c_mii);
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	i2c_mii->name = "SFP I2C Bus";
68162306a36Sopenharmony_ci	i2c_mii->phy_mask = ~0;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	ret = mdiobus_register(i2c_mii);
68462306a36Sopenharmony_ci	if (ret < 0) {
68562306a36Sopenharmony_ci		mdiobus_free(i2c_mii);
68662306a36Sopenharmony_ci		return ret;
68762306a36Sopenharmony_ci	}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	sfp->i2c_mii = i2c_mii;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	return 0;
69262306a36Sopenharmony_ci}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_cistatic void sfp_i2c_mdiobus_destroy(struct sfp *sfp)
69562306a36Sopenharmony_ci{
69662306a36Sopenharmony_ci	mdiobus_unregister(sfp->i2c_mii);
69762306a36Sopenharmony_ci	sfp->i2c_mii = NULL;
69862306a36Sopenharmony_ci}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci/* Interface */
70162306a36Sopenharmony_cistatic int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
70262306a36Sopenharmony_ci{
70362306a36Sopenharmony_ci	return sfp->read(sfp, a2, addr, buf, len);
70462306a36Sopenharmony_ci}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_cistatic int sfp_write(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	return sfp->write(sfp, a2, addr, buf, len);
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_cistatic int sfp_modify_u8(struct sfp *sfp, bool a2, u8 addr, u8 mask, u8 val)
71262306a36Sopenharmony_ci{
71362306a36Sopenharmony_ci	int ret;
71462306a36Sopenharmony_ci	u8 old, v;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	ret = sfp_read(sfp, a2, addr, &old, sizeof(old));
71762306a36Sopenharmony_ci	if (ret != sizeof(old))
71862306a36Sopenharmony_ci		return ret;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	v = (old & ~mask) | (val & mask);
72162306a36Sopenharmony_ci	if (v == old)
72262306a36Sopenharmony_ci		return sizeof(v);
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	return sfp_write(sfp, a2, addr, &v, sizeof(v));
72562306a36Sopenharmony_ci}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_cistatic unsigned int sfp_soft_get_state(struct sfp *sfp)
72862306a36Sopenharmony_ci{
72962306a36Sopenharmony_ci	unsigned int state = 0;
73062306a36Sopenharmony_ci	u8 status;
73162306a36Sopenharmony_ci	int ret;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	ret = sfp_read(sfp, true, SFP_STATUS, &status, sizeof(status));
73462306a36Sopenharmony_ci	if (ret == sizeof(status)) {
73562306a36Sopenharmony_ci		if (status & SFP_STATUS_RX_LOS)
73662306a36Sopenharmony_ci			state |= SFP_F_LOS;
73762306a36Sopenharmony_ci		if (status & SFP_STATUS_TX_FAULT)
73862306a36Sopenharmony_ci			state |= SFP_F_TX_FAULT;
73962306a36Sopenharmony_ci	} else {
74062306a36Sopenharmony_ci		dev_err_ratelimited(sfp->dev,
74162306a36Sopenharmony_ci				    "failed to read SFP soft status: %pe\n",
74262306a36Sopenharmony_ci				    ERR_PTR(ret));
74362306a36Sopenharmony_ci		/* Preserve the current state */
74462306a36Sopenharmony_ci		state = sfp->state;
74562306a36Sopenharmony_ci	}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	return state & sfp->state_soft_mask;
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_cistatic void sfp_soft_set_state(struct sfp *sfp, unsigned int state,
75162306a36Sopenharmony_ci			       unsigned int soft)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	u8 mask = 0;
75462306a36Sopenharmony_ci	u8 val = 0;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	if (soft & SFP_F_TX_DISABLE)
75762306a36Sopenharmony_ci		mask |= SFP_STATUS_TX_DISABLE_FORCE;
75862306a36Sopenharmony_ci	if (state & SFP_F_TX_DISABLE)
75962306a36Sopenharmony_ci		val |= SFP_STATUS_TX_DISABLE_FORCE;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	if (soft & SFP_F_RS0)
76262306a36Sopenharmony_ci		mask |= SFP_STATUS_RS0_SELECT;
76362306a36Sopenharmony_ci	if (state & SFP_F_RS0)
76462306a36Sopenharmony_ci		val |= SFP_STATUS_RS0_SELECT;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	if (mask)
76762306a36Sopenharmony_ci		sfp_modify_u8(sfp, true, SFP_STATUS, mask, val);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	val = mask = 0;
77062306a36Sopenharmony_ci	if (soft & SFP_F_RS1)
77162306a36Sopenharmony_ci		mask |= SFP_EXT_STATUS_RS1_SELECT;
77262306a36Sopenharmony_ci	if (state & SFP_F_RS1)
77362306a36Sopenharmony_ci		val |= SFP_EXT_STATUS_RS1_SELECT;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	if (mask)
77662306a36Sopenharmony_ci		sfp_modify_u8(sfp, true, SFP_EXT_STATUS, mask, val);
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_cistatic void sfp_soft_start_poll(struct sfp *sfp)
78062306a36Sopenharmony_ci{
78162306a36Sopenharmony_ci	const struct sfp_eeprom_id *id = &sfp->id;
78262306a36Sopenharmony_ci	unsigned int mask = 0;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_DISABLE)
78562306a36Sopenharmony_ci		mask |= SFP_F_TX_DISABLE;
78662306a36Sopenharmony_ci	if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_FAULT)
78762306a36Sopenharmony_ci		mask |= SFP_F_TX_FAULT;
78862306a36Sopenharmony_ci	if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS)
78962306a36Sopenharmony_ci		mask |= SFP_F_LOS;
79062306a36Sopenharmony_ci	if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RATE_SELECT)
79162306a36Sopenharmony_ci		mask |= sfp->rs_state_mask;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	mutex_lock(&sfp->st_mutex);
79462306a36Sopenharmony_ci	// Poll the soft state for hardware pins we want to ignore
79562306a36Sopenharmony_ci	sfp->state_soft_mask = ~sfp->state_hw_mask & mask;
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) &&
79862306a36Sopenharmony_ci	    !sfp->need_poll)
79962306a36Sopenharmony_ci		mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
80062306a36Sopenharmony_ci	mutex_unlock(&sfp->st_mutex);
80162306a36Sopenharmony_ci}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_cistatic void sfp_soft_stop_poll(struct sfp *sfp)
80462306a36Sopenharmony_ci{
80562306a36Sopenharmony_ci	mutex_lock(&sfp->st_mutex);
80662306a36Sopenharmony_ci	sfp->state_soft_mask = 0;
80762306a36Sopenharmony_ci	mutex_unlock(&sfp->st_mutex);
80862306a36Sopenharmony_ci}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci/* sfp_get_state() - must be called with st_mutex held, or in the
81162306a36Sopenharmony_ci * initialisation path.
81262306a36Sopenharmony_ci */
81362306a36Sopenharmony_cistatic unsigned int sfp_get_state(struct sfp *sfp)
81462306a36Sopenharmony_ci{
81562306a36Sopenharmony_ci	unsigned int soft = sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT);
81662306a36Sopenharmony_ci	unsigned int state;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	state = sfp->get_state(sfp) & sfp->state_hw_mask;
81962306a36Sopenharmony_ci	if (state & SFP_F_PRESENT && soft)
82062306a36Sopenharmony_ci		state |= sfp_soft_get_state(sfp);
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	return state;
82362306a36Sopenharmony_ci}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci/* sfp_set_state() - must be called with st_mutex held, or in the
82662306a36Sopenharmony_ci * initialisation path.
82762306a36Sopenharmony_ci */
82862306a36Sopenharmony_cistatic void sfp_set_state(struct sfp *sfp, unsigned int state)
82962306a36Sopenharmony_ci{
83062306a36Sopenharmony_ci	unsigned int soft;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	sfp->set_state(sfp, state);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	soft = sfp->state_soft_mask & SFP_F_OUTPUTS;
83562306a36Sopenharmony_ci	if (state & SFP_F_PRESENT && soft)
83662306a36Sopenharmony_ci		sfp_soft_set_state(sfp, state, soft);
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_cistatic void sfp_mod_state(struct sfp *sfp, unsigned int mask, unsigned int set)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci	mutex_lock(&sfp->st_mutex);
84262306a36Sopenharmony_ci	sfp->state = (sfp->state & ~mask) | set;
84362306a36Sopenharmony_ci	sfp_set_state(sfp, sfp->state);
84462306a36Sopenharmony_ci	mutex_unlock(&sfp->st_mutex);
84562306a36Sopenharmony_ci}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_cistatic unsigned int sfp_check(void *buf, size_t len)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	u8 *p, check;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	for (p = buf, check = 0; len; p++, len--)
85262306a36Sopenharmony_ci		check += *p;
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	return check;
85562306a36Sopenharmony_ci}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci/* hwmon */
85862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_HWMON)
85962306a36Sopenharmony_cistatic umode_t sfp_hwmon_is_visible(const void *data,
86062306a36Sopenharmony_ci				    enum hwmon_sensor_types type,
86162306a36Sopenharmony_ci				    u32 attr, int channel)
86262306a36Sopenharmony_ci{
86362306a36Sopenharmony_ci	const struct sfp *sfp = data;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	switch (type) {
86662306a36Sopenharmony_ci	case hwmon_temp:
86762306a36Sopenharmony_ci		switch (attr) {
86862306a36Sopenharmony_ci		case hwmon_temp_min_alarm:
86962306a36Sopenharmony_ci		case hwmon_temp_max_alarm:
87062306a36Sopenharmony_ci		case hwmon_temp_lcrit_alarm:
87162306a36Sopenharmony_ci		case hwmon_temp_crit_alarm:
87262306a36Sopenharmony_ci		case hwmon_temp_min:
87362306a36Sopenharmony_ci		case hwmon_temp_max:
87462306a36Sopenharmony_ci		case hwmon_temp_lcrit:
87562306a36Sopenharmony_ci		case hwmon_temp_crit:
87662306a36Sopenharmony_ci			if (!(sfp->id.ext.enhopts & SFP_ENHOPTS_ALARMWARN))
87762306a36Sopenharmony_ci				return 0;
87862306a36Sopenharmony_ci			fallthrough;
87962306a36Sopenharmony_ci		case hwmon_temp_input:
88062306a36Sopenharmony_ci		case hwmon_temp_label:
88162306a36Sopenharmony_ci			return 0444;
88262306a36Sopenharmony_ci		default:
88362306a36Sopenharmony_ci			return 0;
88462306a36Sopenharmony_ci		}
88562306a36Sopenharmony_ci	case hwmon_in:
88662306a36Sopenharmony_ci		switch (attr) {
88762306a36Sopenharmony_ci		case hwmon_in_min_alarm:
88862306a36Sopenharmony_ci		case hwmon_in_max_alarm:
88962306a36Sopenharmony_ci		case hwmon_in_lcrit_alarm:
89062306a36Sopenharmony_ci		case hwmon_in_crit_alarm:
89162306a36Sopenharmony_ci		case hwmon_in_min:
89262306a36Sopenharmony_ci		case hwmon_in_max:
89362306a36Sopenharmony_ci		case hwmon_in_lcrit:
89462306a36Sopenharmony_ci		case hwmon_in_crit:
89562306a36Sopenharmony_ci			if (!(sfp->id.ext.enhopts & SFP_ENHOPTS_ALARMWARN))
89662306a36Sopenharmony_ci				return 0;
89762306a36Sopenharmony_ci			fallthrough;
89862306a36Sopenharmony_ci		case hwmon_in_input:
89962306a36Sopenharmony_ci		case hwmon_in_label:
90062306a36Sopenharmony_ci			return 0444;
90162306a36Sopenharmony_ci		default:
90262306a36Sopenharmony_ci			return 0;
90362306a36Sopenharmony_ci		}
90462306a36Sopenharmony_ci	case hwmon_curr:
90562306a36Sopenharmony_ci		switch (attr) {
90662306a36Sopenharmony_ci		case hwmon_curr_min_alarm:
90762306a36Sopenharmony_ci		case hwmon_curr_max_alarm:
90862306a36Sopenharmony_ci		case hwmon_curr_lcrit_alarm:
90962306a36Sopenharmony_ci		case hwmon_curr_crit_alarm:
91062306a36Sopenharmony_ci		case hwmon_curr_min:
91162306a36Sopenharmony_ci		case hwmon_curr_max:
91262306a36Sopenharmony_ci		case hwmon_curr_lcrit:
91362306a36Sopenharmony_ci		case hwmon_curr_crit:
91462306a36Sopenharmony_ci			if (!(sfp->id.ext.enhopts & SFP_ENHOPTS_ALARMWARN))
91562306a36Sopenharmony_ci				return 0;
91662306a36Sopenharmony_ci			fallthrough;
91762306a36Sopenharmony_ci		case hwmon_curr_input:
91862306a36Sopenharmony_ci		case hwmon_curr_label:
91962306a36Sopenharmony_ci			return 0444;
92062306a36Sopenharmony_ci		default:
92162306a36Sopenharmony_ci			return 0;
92262306a36Sopenharmony_ci		}
92362306a36Sopenharmony_ci	case hwmon_power:
92462306a36Sopenharmony_ci		/* External calibration of receive power requires
92562306a36Sopenharmony_ci		 * floating point arithmetic. Doing that in the kernel
92662306a36Sopenharmony_ci		 * is not easy, so just skip it. If the module does
92762306a36Sopenharmony_ci		 * not require external calibration, we can however
92862306a36Sopenharmony_ci		 * show receiver power, since FP is then not needed.
92962306a36Sopenharmony_ci		 */
93062306a36Sopenharmony_ci		if (sfp->id.ext.diagmon & SFP_DIAGMON_EXT_CAL &&
93162306a36Sopenharmony_ci		    channel == 1)
93262306a36Sopenharmony_ci			return 0;
93362306a36Sopenharmony_ci		switch (attr) {
93462306a36Sopenharmony_ci		case hwmon_power_min_alarm:
93562306a36Sopenharmony_ci		case hwmon_power_max_alarm:
93662306a36Sopenharmony_ci		case hwmon_power_lcrit_alarm:
93762306a36Sopenharmony_ci		case hwmon_power_crit_alarm:
93862306a36Sopenharmony_ci		case hwmon_power_min:
93962306a36Sopenharmony_ci		case hwmon_power_max:
94062306a36Sopenharmony_ci		case hwmon_power_lcrit:
94162306a36Sopenharmony_ci		case hwmon_power_crit:
94262306a36Sopenharmony_ci			if (!(sfp->id.ext.enhopts & SFP_ENHOPTS_ALARMWARN))
94362306a36Sopenharmony_ci				return 0;
94462306a36Sopenharmony_ci			fallthrough;
94562306a36Sopenharmony_ci		case hwmon_power_input:
94662306a36Sopenharmony_ci		case hwmon_power_label:
94762306a36Sopenharmony_ci			return 0444;
94862306a36Sopenharmony_ci		default:
94962306a36Sopenharmony_ci			return 0;
95062306a36Sopenharmony_ci		}
95162306a36Sopenharmony_ci	default:
95262306a36Sopenharmony_ci		return 0;
95362306a36Sopenharmony_ci	}
95462306a36Sopenharmony_ci}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_cistatic int sfp_hwmon_read_sensor(struct sfp *sfp, int reg, long *value)
95762306a36Sopenharmony_ci{
95862306a36Sopenharmony_ci	__be16 val;
95962306a36Sopenharmony_ci	int err;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	err = sfp_read(sfp, true, reg, &val, sizeof(val));
96262306a36Sopenharmony_ci	if (err < 0)
96362306a36Sopenharmony_ci		return err;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	*value = be16_to_cpu(val);
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	return 0;
96862306a36Sopenharmony_ci}
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_cistatic void sfp_hwmon_to_rx_power(long *value)
97162306a36Sopenharmony_ci{
97262306a36Sopenharmony_ci	*value = DIV_ROUND_CLOSEST(*value, 10);
97362306a36Sopenharmony_ci}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_cistatic void sfp_hwmon_calibrate(struct sfp *sfp, unsigned int slope, int offset,
97662306a36Sopenharmony_ci				long *value)
97762306a36Sopenharmony_ci{
97862306a36Sopenharmony_ci	if (sfp->id.ext.diagmon & SFP_DIAGMON_EXT_CAL)
97962306a36Sopenharmony_ci		*value = DIV_ROUND_CLOSEST(*value * slope, 256) + offset;
98062306a36Sopenharmony_ci}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_cistatic void sfp_hwmon_calibrate_temp(struct sfp *sfp, long *value)
98362306a36Sopenharmony_ci{
98462306a36Sopenharmony_ci	sfp_hwmon_calibrate(sfp, be16_to_cpu(sfp->diag.cal_t_slope),
98562306a36Sopenharmony_ci			    be16_to_cpu(sfp->diag.cal_t_offset), value);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	if (*value >= 0x8000)
98862306a36Sopenharmony_ci		*value -= 0x10000;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	*value = DIV_ROUND_CLOSEST(*value * 1000, 256);
99162306a36Sopenharmony_ci}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_cistatic void sfp_hwmon_calibrate_vcc(struct sfp *sfp, long *value)
99462306a36Sopenharmony_ci{
99562306a36Sopenharmony_ci	sfp_hwmon_calibrate(sfp, be16_to_cpu(sfp->diag.cal_v_slope),
99662306a36Sopenharmony_ci			    be16_to_cpu(sfp->diag.cal_v_offset), value);
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	*value = DIV_ROUND_CLOSEST(*value, 10);
99962306a36Sopenharmony_ci}
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_cistatic void sfp_hwmon_calibrate_bias(struct sfp *sfp, long *value)
100262306a36Sopenharmony_ci{
100362306a36Sopenharmony_ci	sfp_hwmon_calibrate(sfp, be16_to_cpu(sfp->diag.cal_txi_slope),
100462306a36Sopenharmony_ci			    be16_to_cpu(sfp->diag.cal_txi_offset), value);
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	*value = DIV_ROUND_CLOSEST(*value, 500);
100762306a36Sopenharmony_ci}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_cistatic void sfp_hwmon_calibrate_tx_power(struct sfp *sfp, long *value)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	sfp_hwmon_calibrate(sfp, be16_to_cpu(sfp->diag.cal_txpwr_slope),
101262306a36Sopenharmony_ci			    be16_to_cpu(sfp->diag.cal_txpwr_offset), value);
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	*value = DIV_ROUND_CLOSEST(*value, 10);
101562306a36Sopenharmony_ci}
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_cistatic int sfp_hwmon_read_temp(struct sfp *sfp, int reg, long *value)
101862306a36Sopenharmony_ci{
101962306a36Sopenharmony_ci	int err;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	err = sfp_hwmon_read_sensor(sfp, reg, value);
102262306a36Sopenharmony_ci	if (err < 0)
102362306a36Sopenharmony_ci		return err;
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	sfp_hwmon_calibrate_temp(sfp, value);
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	return 0;
102862306a36Sopenharmony_ci}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_cistatic int sfp_hwmon_read_vcc(struct sfp *sfp, int reg, long *value)
103162306a36Sopenharmony_ci{
103262306a36Sopenharmony_ci	int err;
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	err = sfp_hwmon_read_sensor(sfp, reg, value);
103562306a36Sopenharmony_ci	if (err < 0)
103662306a36Sopenharmony_ci		return err;
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	sfp_hwmon_calibrate_vcc(sfp, value);
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	return 0;
104162306a36Sopenharmony_ci}
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_cistatic int sfp_hwmon_read_bias(struct sfp *sfp, int reg, long *value)
104462306a36Sopenharmony_ci{
104562306a36Sopenharmony_ci	int err;
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	err = sfp_hwmon_read_sensor(sfp, reg, value);
104862306a36Sopenharmony_ci	if (err < 0)
104962306a36Sopenharmony_ci		return err;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	sfp_hwmon_calibrate_bias(sfp, value);
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	return 0;
105462306a36Sopenharmony_ci}
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_cistatic int sfp_hwmon_read_tx_power(struct sfp *sfp, int reg, long *value)
105762306a36Sopenharmony_ci{
105862306a36Sopenharmony_ci	int err;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	err = sfp_hwmon_read_sensor(sfp, reg, value);
106162306a36Sopenharmony_ci	if (err < 0)
106262306a36Sopenharmony_ci		return err;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	sfp_hwmon_calibrate_tx_power(sfp, value);
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	return 0;
106762306a36Sopenharmony_ci}
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_cistatic int sfp_hwmon_read_rx_power(struct sfp *sfp, int reg, long *value)
107062306a36Sopenharmony_ci{
107162306a36Sopenharmony_ci	int err;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	err = sfp_hwmon_read_sensor(sfp, reg, value);
107462306a36Sopenharmony_ci	if (err < 0)
107562306a36Sopenharmony_ci		return err;
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	sfp_hwmon_to_rx_power(value);
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	return 0;
108062306a36Sopenharmony_ci}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_cistatic int sfp_hwmon_temp(struct sfp *sfp, u32 attr, long *value)
108362306a36Sopenharmony_ci{
108462306a36Sopenharmony_ci	u8 status;
108562306a36Sopenharmony_ci	int err;
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	switch (attr) {
108862306a36Sopenharmony_ci	case hwmon_temp_input:
108962306a36Sopenharmony_ci		return sfp_hwmon_read_temp(sfp, SFP_TEMP, value);
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	case hwmon_temp_lcrit:
109262306a36Sopenharmony_ci		*value = be16_to_cpu(sfp->diag.temp_low_alarm);
109362306a36Sopenharmony_ci		sfp_hwmon_calibrate_temp(sfp, value);
109462306a36Sopenharmony_ci		return 0;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	case hwmon_temp_min:
109762306a36Sopenharmony_ci		*value = be16_to_cpu(sfp->diag.temp_low_warn);
109862306a36Sopenharmony_ci		sfp_hwmon_calibrate_temp(sfp, value);
109962306a36Sopenharmony_ci		return 0;
110062306a36Sopenharmony_ci	case hwmon_temp_max:
110162306a36Sopenharmony_ci		*value = be16_to_cpu(sfp->diag.temp_high_warn);
110262306a36Sopenharmony_ci		sfp_hwmon_calibrate_temp(sfp, value);
110362306a36Sopenharmony_ci		return 0;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	case hwmon_temp_crit:
110662306a36Sopenharmony_ci		*value = be16_to_cpu(sfp->diag.temp_high_alarm);
110762306a36Sopenharmony_ci		sfp_hwmon_calibrate_temp(sfp, value);
110862306a36Sopenharmony_ci		return 0;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	case hwmon_temp_lcrit_alarm:
111162306a36Sopenharmony_ci		err = sfp_read(sfp, true, SFP_ALARM0, &status, sizeof(status));
111262306a36Sopenharmony_ci		if (err < 0)
111362306a36Sopenharmony_ci			return err;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci		*value = !!(status & SFP_ALARM0_TEMP_LOW);
111662306a36Sopenharmony_ci		return 0;
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	case hwmon_temp_min_alarm:
111962306a36Sopenharmony_ci		err = sfp_read(sfp, true, SFP_WARN0, &status, sizeof(status));
112062306a36Sopenharmony_ci		if (err < 0)
112162306a36Sopenharmony_ci			return err;
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci		*value = !!(status & SFP_WARN0_TEMP_LOW);
112462306a36Sopenharmony_ci		return 0;
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	case hwmon_temp_max_alarm:
112762306a36Sopenharmony_ci		err = sfp_read(sfp, true, SFP_WARN0, &status, sizeof(status));
112862306a36Sopenharmony_ci		if (err < 0)
112962306a36Sopenharmony_ci			return err;
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci		*value = !!(status & SFP_WARN0_TEMP_HIGH);
113262306a36Sopenharmony_ci		return 0;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	case hwmon_temp_crit_alarm:
113562306a36Sopenharmony_ci		err = sfp_read(sfp, true, SFP_ALARM0, &status, sizeof(status));
113662306a36Sopenharmony_ci		if (err < 0)
113762306a36Sopenharmony_ci			return err;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci		*value = !!(status & SFP_ALARM0_TEMP_HIGH);
114062306a36Sopenharmony_ci		return 0;
114162306a36Sopenharmony_ci	default:
114262306a36Sopenharmony_ci		return -EOPNOTSUPP;
114362306a36Sopenharmony_ci	}
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	return -EOPNOTSUPP;
114662306a36Sopenharmony_ci}
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_cistatic int sfp_hwmon_vcc(struct sfp *sfp, u32 attr, long *value)
114962306a36Sopenharmony_ci{
115062306a36Sopenharmony_ci	u8 status;
115162306a36Sopenharmony_ci	int err;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	switch (attr) {
115462306a36Sopenharmony_ci	case hwmon_in_input:
115562306a36Sopenharmony_ci		return sfp_hwmon_read_vcc(sfp, SFP_VCC, value);
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	case hwmon_in_lcrit:
115862306a36Sopenharmony_ci		*value = be16_to_cpu(sfp->diag.volt_low_alarm);
115962306a36Sopenharmony_ci		sfp_hwmon_calibrate_vcc(sfp, value);
116062306a36Sopenharmony_ci		return 0;
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	case hwmon_in_min:
116362306a36Sopenharmony_ci		*value = be16_to_cpu(sfp->diag.volt_low_warn);
116462306a36Sopenharmony_ci		sfp_hwmon_calibrate_vcc(sfp, value);
116562306a36Sopenharmony_ci		return 0;
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	case hwmon_in_max:
116862306a36Sopenharmony_ci		*value = be16_to_cpu(sfp->diag.volt_high_warn);
116962306a36Sopenharmony_ci		sfp_hwmon_calibrate_vcc(sfp, value);
117062306a36Sopenharmony_ci		return 0;
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	case hwmon_in_crit:
117362306a36Sopenharmony_ci		*value = be16_to_cpu(sfp->diag.volt_high_alarm);
117462306a36Sopenharmony_ci		sfp_hwmon_calibrate_vcc(sfp, value);
117562306a36Sopenharmony_ci		return 0;
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	case hwmon_in_lcrit_alarm:
117862306a36Sopenharmony_ci		err = sfp_read(sfp, true, SFP_ALARM0, &status, sizeof(status));
117962306a36Sopenharmony_ci		if (err < 0)
118062306a36Sopenharmony_ci			return err;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci		*value = !!(status & SFP_ALARM0_VCC_LOW);
118362306a36Sopenharmony_ci		return 0;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	case hwmon_in_min_alarm:
118662306a36Sopenharmony_ci		err = sfp_read(sfp, true, SFP_WARN0, &status, sizeof(status));
118762306a36Sopenharmony_ci		if (err < 0)
118862306a36Sopenharmony_ci			return err;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci		*value = !!(status & SFP_WARN0_VCC_LOW);
119162306a36Sopenharmony_ci		return 0;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	case hwmon_in_max_alarm:
119462306a36Sopenharmony_ci		err = sfp_read(sfp, true, SFP_WARN0, &status, sizeof(status));
119562306a36Sopenharmony_ci		if (err < 0)
119662306a36Sopenharmony_ci			return err;
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci		*value = !!(status & SFP_WARN0_VCC_HIGH);
119962306a36Sopenharmony_ci		return 0;
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	case hwmon_in_crit_alarm:
120262306a36Sopenharmony_ci		err = sfp_read(sfp, true, SFP_ALARM0, &status, sizeof(status));
120362306a36Sopenharmony_ci		if (err < 0)
120462306a36Sopenharmony_ci			return err;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci		*value = !!(status & SFP_ALARM0_VCC_HIGH);
120762306a36Sopenharmony_ci		return 0;
120862306a36Sopenharmony_ci	default:
120962306a36Sopenharmony_ci		return -EOPNOTSUPP;
121062306a36Sopenharmony_ci	}
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	return -EOPNOTSUPP;
121362306a36Sopenharmony_ci}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_cistatic int sfp_hwmon_bias(struct sfp *sfp, u32 attr, long *value)
121662306a36Sopenharmony_ci{
121762306a36Sopenharmony_ci	u8 status;
121862306a36Sopenharmony_ci	int err;
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	switch (attr) {
122162306a36Sopenharmony_ci	case hwmon_curr_input:
122262306a36Sopenharmony_ci		return sfp_hwmon_read_bias(sfp, SFP_TX_BIAS, value);
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	case hwmon_curr_lcrit:
122562306a36Sopenharmony_ci		*value = be16_to_cpu(sfp->diag.bias_low_alarm);
122662306a36Sopenharmony_ci		sfp_hwmon_calibrate_bias(sfp, value);
122762306a36Sopenharmony_ci		return 0;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	case hwmon_curr_min:
123062306a36Sopenharmony_ci		*value = be16_to_cpu(sfp->diag.bias_low_warn);
123162306a36Sopenharmony_ci		sfp_hwmon_calibrate_bias(sfp, value);
123262306a36Sopenharmony_ci		return 0;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	case hwmon_curr_max:
123562306a36Sopenharmony_ci		*value = be16_to_cpu(sfp->diag.bias_high_warn);
123662306a36Sopenharmony_ci		sfp_hwmon_calibrate_bias(sfp, value);
123762306a36Sopenharmony_ci		return 0;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	case hwmon_curr_crit:
124062306a36Sopenharmony_ci		*value = be16_to_cpu(sfp->diag.bias_high_alarm);
124162306a36Sopenharmony_ci		sfp_hwmon_calibrate_bias(sfp, value);
124262306a36Sopenharmony_ci		return 0;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	case hwmon_curr_lcrit_alarm:
124562306a36Sopenharmony_ci		err = sfp_read(sfp, true, SFP_ALARM0, &status, sizeof(status));
124662306a36Sopenharmony_ci		if (err < 0)
124762306a36Sopenharmony_ci			return err;
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci		*value = !!(status & SFP_ALARM0_TX_BIAS_LOW);
125062306a36Sopenharmony_ci		return 0;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	case hwmon_curr_min_alarm:
125362306a36Sopenharmony_ci		err = sfp_read(sfp, true, SFP_WARN0, &status, sizeof(status));
125462306a36Sopenharmony_ci		if (err < 0)
125562306a36Sopenharmony_ci			return err;
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci		*value = !!(status & SFP_WARN0_TX_BIAS_LOW);
125862306a36Sopenharmony_ci		return 0;
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	case hwmon_curr_max_alarm:
126162306a36Sopenharmony_ci		err = sfp_read(sfp, true, SFP_WARN0, &status, sizeof(status));
126262306a36Sopenharmony_ci		if (err < 0)
126362306a36Sopenharmony_ci			return err;
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci		*value = !!(status & SFP_WARN0_TX_BIAS_HIGH);
126662306a36Sopenharmony_ci		return 0;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	case hwmon_curr_crit_alarm:
126962306a36Sopenharmony_ci		err = sfp_read(sfp, true, SFP_ALARM0, &status, sizeof(status));
127062306a36Sopenharmony_ci		if (err < 0)
127162306a36Sopenharmony_ci			return err;
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci		*value = !!(status & SFP_ALARM0_TX_BIAS_HIGH);
127462306a36Sopenharmony_ci		return 0;
127562306a36Sopenharmony_ci	default:
127662306a36Sopenharmony_ci		return -EOPNOTSUPP;
127762306a36Sopenharmony_ci	}
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	return -EOPNOTSUPP;
128062306a36Sopenharmony_ci}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_cistatic int sfp_hwmon_tx_power(struct sfp *sfp, u32 attr, long *value)
128362306a36Sopenharmony_ci{
128462306a36Sopenharmony_ci	u8 status;
128562306a36Sopenharmony_ci	int err;
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	switch (attr) {
128862306a36Sopenharmony_ci	case hwmon_power_input:
128962306a36Sopenharmony_ci		return sfp_hwmon_read_tx_power(sfp, SFP_TX_POWER, value);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	case hwmon_power_lcrit:
129262306a36Sopenharmony_ci		*value = be16_to_cpu(sfp->diag.txpwr_low_alarm);
129362306a36Sopenharmony_ci		sfp_hwmon_calibrate_tx_power(sfp, value);
129462306a36Sopenharmony_ci		return 0;
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	case hwmon_power_min:
129762306a36Sopenharmony_ci		*value = be16_to_cpu(sfp->diag.txpwr_low_warn);
129862306a36Sopenharmony_ci		sfp_hwmon_calibrate_tx_power(sfp, value);
129962306a36Sopenharmony_ci		return 0;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	case hwmon_power_max:
130262306a36Sopenharmony_ci		*value = be16_to_cpu(sfp->diag.txpwr_high_warn);
130362306a36Sopenharmony_ci		sfp_hwmon_calibrate_tx_power(sfp, value);
130462306a36Sopenharmony_ci		return 0;
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	case hwmon_power_crit:
130762306a36Sopenharmony_ci		*value = be16_to_cpu(sfp->diag.txpwr_high_alarm);
130862306a36Sopenharmony_ci		sfp_hwmon_calibrate_tx_power(sfp, value);
130962306a36Sopenharmony_ci		return 0;
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	case hwmon_power_lcrit_alarm:
131262306a36Sopenharmony_ci		err = sfp_read(sfp, true, SFP_ALARM0, &status, sizeof(status));
131362306a36Sopenharmony_ci		if (err < 0)
131462306a36Sopenharmony_ci			return err;
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci		*value = !!(status & SFP_ALARM0_TXPWR_LOW);
131762306a36Sopenharmony_ci		return 0;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	case hwmon_power_min_alarm:
132062306a36Sopenharmony_ci		err = sfp_read(sfp, true, SFP_WARN0, &status, sizeof(status));
132162306a36Sopenharmony_ci		if (err < 0)
132262306a36Sopenharmony_ci			return err;
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci		*value = !!(status & SFP_WARN0_TXPWR_LOW);
132562306a36Sopenharmony_ci		return 0;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	case hwmon_power_max_alarm:
132862306a36Sopenharmony_ci		err = sfp_read(sfp, true, SFP_WARN0, &status, sizeof(status));
132962306a36Sopenharmony_ci		if (err < 0)
133062306a36Sopenharmony_ci			return err;
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci		*value = !!(status & SFP_WARN0_TXPWR_HIGH);
133362306a36Sopenharmony_ci		return 0;
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	case hwmon_power_crit_alarm:
133662306a36Sopenharmony_ci		err = sfp_read(sfp, true, SFP_ALARM0, &status, sizeof(status));
133762306a36Sopenharmony_ci		if (err < 0)
133862306a36Sopenharmony_ci			return err;
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci		*value = !!(status & SFP_ALARM0_TXPWR_HIGH);
134162306a36Sopenharmony_ci		return 0;
134262306a36Sopenharmony_ci	default:
134362306a36Sopenharmony_ci		return -EOPNOTSUPP;
134462306a36Sopenharmony_ci	}
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	return -EOPNOTSUPP;
134762306a36Sopenharmony_ci}
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_cistatic int sfp_hwmon_rx_power(struct sfp *sfp, u32 attr, long *value)
135062306a36Sopenharmony_ci{
135162306a36Sopenharmony_ci	u8 status;
135262306a36Sopenharmony_ci	int err;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	switch (attr) {
135562306a36Sopenharmony_ci	case hwmon_power_input:
135662306a36Sopenharmony_ci		return sfp_hwmon_read_rx_power(sfp, SFP_RX_POWER, value);
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	case hwmon_power_lcrit:
135962306a36Sopenharmony_ci		*value = be16_to_cpu(sfp->diag.rxpwr_low_alarm);
136062306a36Sopenharmony_ci		sfp_hwmon_to_rx_power(value);
136162306a36Sopenharmony_ci		return 0;
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	case hwmon_power_min:
136462306a36Sopenharmony_ci		*value = be16_to_cpu(sfp->diag.rxpwr_low_warn);
136562306a36Sopenharmony_ci		sfp_hwmon_to_rx_power(value);
136662306a36Sopenharmony_ci		return 0;
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	case hwmon_power_max:
136962306a36Sopenharmony_ci		*value = be16_to_cpu(sfp->diag.rxpwr_high_warn);
137062306a36Sopenharmony_ci		sfp_hwmon_to_rx_power(value);
137162306a36Sopenharmony_ci		return 0;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	case hwmon_power_crit:
137462306a36Sopenharmony_ci		*value = be16_to_cpu(sfp->diag.rxpwr_high_alarm);
137562306a36Sopenharmony_ci		sfp_hwmon_to_rx_power(value);
137662306a36Sopenharmony_ci		return 0;
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	case hwmon_power_lcrit_alarm:
137962306a36Sopenharmony_ci		err = sfp_read(sfp, true, SFP_ALARM1, &status, sizeof(status));
138062306a36Sopenharmony_ci		if (err < 0)
138162306a36Sopenharmony_ci			return err;
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci		*value = !!(status & SFP_ALARM1_RXPWR_LOW);
138462306a36Sopenharmony_ci		return 0;
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	case hwmon_power_min_alarm:
138762306a36Sopenharmony_ci		err = sfp_read(sfp, true, SFP_WARN1, &status, sizeof(status));
138862306a36Sopenharmony_ci		if (err < 0)
138962306a36Sopenharmony_ci			return err;
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci		*value = !!(status & SFP_WARN1_RXPWR_LOW);
139262306a36Sopenharmony_ci		return 0;
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	case hwmon_power_max_alarm:
139562306a36Sopenharmony_ci		err = sfp_read(sfp, true, SFP_WARN1, &status, sizeof(status));
139662306a36Sopenharmony_ci		if (err < 0)
139762306a36Sopenharmony_ci			return err;
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci		*value = !!(status & SFP_WARN1_RXPWR_HIGH);
140062306a36Sopenharmony_ci		return 0;
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	case hwmon_power_crit_alarm:
140362306a36Sopenharmony_ci		err = sfp_read(sfp, true, SFP_ALARM1, &status, sizeof(status));
140462306a36Sopenharmony_ci		if (err < 0)
140562306a36Sopenharmony_ci			return err;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci		*value = !!(status & SFP_ALARM1_RXPWR_HIGH);
140862306a36Sopenharmony_ci		return 0;
140962306a36Sopenharmony_ci	default:
141062306a36Sopenharmony_ci		return -EOPNOTSUPP;
141162306a36Sopenharmony_ci	}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	return -EOPNOTSUPP;
141462306a36Sopenharmony_ci}
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_cistatic int sfp_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
141762306a36Sopenharmony_ci			  u32 attr, int channel, long *value)
141862306a36Sopenharmony_ci{
141962306a36Sopenharmony_ci	struct sfp *sfp = dev_get_drvdata(dev);
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	switch (type) {
142262306a36Sopenharmony_ci	case hwmon_temp:
142362306a36Sopenharmony_ci		return sfp_hwmon_temp(sfp, attr, value);
142462306a36Sopenharmony_ci	case hwmon_in:
142562306a36Sopenharmony_ci		return sfp_hwmon_vcc(sfp, attr, value);
142662306a36Sopenharmony_ci	case hwmon_curr:
142762306a36Sopenharmony_ci		return sfp_hwmon_bias(sfp, attr, value);
142862306a36Sopenharmony_ci	case hwmon_power:
142962306a36Sopenharmony_ci		switch (channel) {
143062306a36Sopenharmony_ci		case 0:
143162306a36Sopenharmony_ci			return sfp_hwmon_tx_power(sfp, attr, value);
143262306a36Sopenharmony_ci		case 1:
143362306a36Sopenharmony_ci			return sfp_hwmon_rx_power(sfp, attr, value);
143462306a36Sopenharmony_ci		default:
143562306a36Sopenharmony_ci			return -EOPNOTSUPP;
143662306a36Sopenharmony_ci		}
143762306a36Sopenharmony_ci	default:
143862306a36Sopenharmony_ci		return -EOPNOTSUPP;
143962306a36Sopenharmony_ci	}
144062306a36Sopenharmony_ci}
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_cistatic const char *const sfp_hwmon_power_labels[] = {
144362306a36Sopenharmony_ci	"TX_power",
144462306a36Sopenharmony_ci	"RX_power",
144562306a36Sopenharmony_ci};
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_cistatic int sfp_hwmon_read_string(struct device *dev,
144862306a36Sopenharmony_ci				 enum hwmon_sensor_types type,
144962306a36Sopenharmony_ci				 u32 attr, int channel, const char **str)
145062306a36Sopenharmony_ci{
145162306a36Sopenharmony_ci	switch (type) {
145262306a36Sopenharmony_ci	case hwmon_curr:
145362306a36Sopenharmony_ci		switch (attr) {
145462306a36Sopenharmony_ci		case hwmon_curr_label:
145562306a36Sopenharmony_ci			*str = "bias";
145662306a36Sopenharmony_ci			return 0;
145762306a36Sopenharmony_ci		default:
145862306a36Sopenharmony_ci			return -EOPNOTSUPP;
145962306a36Sopenharmony_ci		}
146062306a36Sopenharmony_ci		break;
146162306a36Sopenharmony_ci	case hwmon_temp:
146262306a36Sopenharmony_ci		switch (attr) {
146362306a36Sopenharmony_ci		case hwmon_temp_label:
146462306a36Sopenharmony_ci			*str = "temperature";
146562306a36Sopenharmony_ci			return 0;
146662306a36Sopenharmony_ci		default:
146762306a36Sopenharmony_ci			return -EOPNOTSUPP;
146862306a36Sopenharmony_ci		}
146962306a36Sopenharmony_ci		break;
147062306a36Sopenharmony_ci	case hwmon_in:
147162306a36Sopenharmony_ci		switch (attr) {
147262306a36Sopenharmony_ci		case hwmon_in_label:
147362306a36Sopenharmony_ci			*str = "VCC";
147462306a36Sopenharmony_ci			return 0;
147562306a36Sopenharmony_ci		default:
147662306a36Sopenharmony_ci			return -EOPNOTSUPP;
147762306a36Sopenharmony_ci		}
147862306a36Sopenharmony_ci		break;
147962306a36Sopenharmony_ci	case hwmon_power:
148062306a36Sopenharmony_ci		switch (attr) {
148162306a36Sopenharmony_ci		case hwmon_power_label:
148262306a36Sopenharmony_ci			*str = sfp_hwmon_power_labels[channel];
148362306a36Sopenharmony_ci			return 0;
148462306a36Sopenharmony_ci		default:
148562306a36Sopenharmony_ci			return -EOPNOTSUPP;
148662306a36Sopenharmony_ci		}
148762306a36Sopenharmony_ci		break;
148862306a36Sopenharmony_ci	default:
148962306a36Sopenharmony_ci		return -EOPNOTSUPP;
149062306a36Sopenharmony_ci	}
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	return -EOPNOTSUPP;
149362306a36Sopenharmony_ci}
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_cistatic const struct hwmon_ops sfp_hwmon_ops = {
149662306a36Sopenharmony_ci	.is_visible = sfp_hwmon_is_visible,
149762306a36Sopenharmony_ci	.read = sfp_hwmon_read,
149862306a36Sopenharmony_ci	.read_string = sfp_hwmon_read_string,
149962306a36Sopenharmony_ci};
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_cistatic const struct hwmon_channel_info * const sfp_hwmon_info[] = {
150262306a36Sopenharmony_ci	HWMON_CHANNEL_INFO(chip,
150362306a36Sopenharmony_ci			   HWMON_C_REGISTER_TZ),
150462306a36Sopenharmony_ci	HWMON_CHANNEL_INFO(in,
150562306a36Sopenharmony_ci			   HWMON_I_INPUT |
150662306a36Sopenharmony_ci			   HWMON_I_MAX | HWMON_I_MIN |
150762306a36Sopenharmony_ci			   HWMON_I_MAX_ALARM | HWMON_I_MIN_ALARM |
150862306a36Sopenharmony_ci			   HWMON_I_CRIT | HWMON_I_LCRIT |
150962306a36Sopenharmony_ci			   HWMON_I_CRIT_ALARM | HWMON_I_LCRIT_ALARM |
151062306a36Sopenharmony_ci			   HWMON_I_LABEL),
151162306a36Sopenharmony_ci	HWMON_CHANNEL_INFO(temp,
151262306a36Sopenharmony_ci			   HWMON_T_INPUT |
151362306a36Sopenharmony_ci			   HWMON_T_MAX | HWMON_T_MIN |
151462306a36Sopenharmony_ci			   HWMON_T_MAX_ALARM | HWMON_T_MIN_ALARM |
151562306a36Sopenharmony_ci			   HWMON_T_CRIT | HWMON_T_LCRIT |
151662306a36Sopenharmony_ci			   HWMON_T_CRIT_ALARM | HWMON_T_LCRIT_ALARM |
151762306a36Sopenharmony_ci			   HWMON_T_LABEL),
151862306a36Sopenharmony_ci	HWMON_CHANNEL_INFO(curr,
151962306a36Sopenharmony_ci			   HWMON_C_INPUT |
152062306a36Sopenharmony_ci			   HWMON_C_MAX | HWMON_C_MIN |
152162306a36Sopenharmony_ci			   HWMON_C_MAX_ALARM | HWMON_C_MIN_ALARM |
152262306a36Sopenharmony_ci			   HWMON_C_CRIT | HWMON_C_LCRIT |
152362306a36Sopenharmony_ci			   HWMON_C_CRIT_ALARM | HWMON_C_LCRIT_ALARM |
152462306a36Sopenharmony_ci			   HWMON_C_LABEL),
152562306a36Sopenharmony_ci	HWMON_CHANNEL_INFO(power,
152662306a36Sopenharmony_ci			   /* Transmit power */
152762306a36Sopenharmony_ci			   HWMON_P_INPUT |
152862306a36Sopenharmony_ci			   HWMON_P_MAX | HWMON_P_MIN |
152962306a36Sopenharmony_ci			   HWMON_P_MAX_ALARM | HWMON_P_MIN_ALARM |
153062306a36Sopenharmony_ci			   HWMON_P_CRIT | HWMON_P_LCRIT |
153162306a36Sopenharmony_ci			   HWMON_P_CRIT_ALARM | HWMON_P_LCRIT_ALARM |
153262306a36Sopenharmony_ci			   HWMON_P_LABEL,
153362306a36Sopenharmony_ci			   /* Receive power */
153462306a36Sopenharmony_ci			   HWMON_P_INPUT |
153562306a36Sopenharmony_ci			   HWMON_P_MAX | HWMON_P_MIN |
153662306a36Sopenharmony_ci			   HWMON_P_MAX_ALARM | HWMON_P_MIN_ALARM |
153762306a36Sopenharmony_ci			   HWMON_P_CRIT | HWMON_P_LCRIT |
153862306a36Sopenharmony_ci			   HWMON_P_CRIT_ALARM | HWMON_P_LCRIT_ALARM |
153962306a36Sopenharmony_ci			   HWMON_P_LABEL),
154062306a36Sopenharmony_ci	NULL,
154162306a36Sopenharmony_ci};
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_cistatic const struct hwmon_chip_info sfp_hwmon_chip_info = {
154462306a36Sopenharmony_ci	.ops = &sfp_hwmon_ops,
154562306a36Sopenharmony_ci	.info = sfp_hwmon_info,
154662306a36Sopenharmony_ci};
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_cistatic void sfp_hwmon_probe(struct work_struct *work)
154962306a36Sopenharmony_ci{
155062306a36Sopenharmony_ci	struct sfp *sfp = container_of(work, struct sfp, hwmon_probe.work);
155162306a36Sopenharmony_ci	int err;
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	/* hwmon interface needs to access 16bit registers in atomic way to
155462306a36Sopenharmony_ci	 * guarantee coherency of the diagnostic monitoring data. If it is not
155562306a36Sopenharmony_ci	 * possible to guarantee coherency because EEPROM is broken in such way
155662306a36Sopenharmony_ci	 * that does not support atomic 16bit read operation then we have to
155762306a36Sopenharmony_ci	 * skip registration of hwmon device.
155862306a36Sopenharmony_ci	 */
155962306a36Sopenharmony_ci	if (sfp->i2c_block_size < 2) {
156062306a36Sopenharmony_ci		dev_info(sfp->dev,
156162306a36Sopenharmony_ci			 "skipping hwmon device registration due to broken EEPROM\n");
156262306a36Sopenharmony_ci		dev_info(sfp->dev,
156362306a36Sopenharmony_ci			 "diagnostic EEPROM area cannot be read atomically to guarantee data coherency\n");
156462306a36Sopenharmony_ci		return;
156562306a36Sopenharmony_ci	}
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	err = sfp_read(sfp, true, 0, &sfp->diag, sizeof(sfp->diag));
156862306a36Sopenharmony_ci	if (err < 0) {
156962306a36Sopenharmony_ci		if (sfp->hwmon_tries--) {
157062306a36Sopenharmony_ci			mod_delayed_work(system_wq, &sfp->hwmon_probe,
157162306a36Sopenharmony_ci					 T_PROBE_RETRY_SLOW);
157262306a36Sopenharmony_ci		} else {
157362306a36Sopenharmony_ci			dev_warn(sfp->dev, "hwmon probe failed: %pe\n",
157462306a36Sopenharmony_ci				 ERR_PTR(err));
157562306a36Sopenharmony_ci		}
157662306a36Sopenharmony_ci		return;
157762306a36Sopenharmony_ci	}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	sfp->hwmon_name = hwmon_sanitize_name(dev_name(sfp->dev));
158062306a36Sopenharmony_ci	if (IS_ERR(sfp->hwmon_name)) {
158162306a36Sopenharmony_ci		dev_err(sfp->dev, "out of memory for hwmon name\n");
158262306a36Sopenharmony_ci		return;
158362306a36Sopenharmony_ci	}
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	sfp->hwmon_dev = hwmon_device_register_with_info(sfp->dev,
158662306a36Sopenharmony_ci							 sfp->hwmon_name, sfp,
158762306a36Sopenharmony_ci							 &sfp_hwmon_chip_info,
158862306a36Sopenharmony_ci							 NULL);
158962306a36Sopenharmony_ci	if (IS_ERR(sfp->hwmon_dev))
159062306a36Sopenharmony_ci		dev_err(sfp->dev, "failed to register hwmon device: %ld\n",
159162306a36Sopenharmony_ci			PTR_ERR(sfp->hwmon_dev));
159262306a36Sopenharmony_ci}
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_cistatic int sfp_hwmon_insert(struct sfp *sfp)
159562306a36Sopenharmony_ci{
159662306a36Sopenharmony_ci	if (sfp->have_a2 && sfp->id.ext.diagmon & SFP_DIAGMON_DDM) {
159762306a36Sopenharmony_ci		mod_delayed_work(system_wq, &sfp->hwmon_probe, 1);
159862306a36Sopenharmony_ci		sfp->hwmon_tries = R_PROBE_RETRY_SLOW;
159962306a36Sopenharmony_ci	}
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	return 0;
160262306a36Sopenharmony_ci}
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_cistatic void sfp_hwmon_remove(struct sfp *sfp)
160562306a36Sopenharmony_ci{
160662306a36Sopenharmony_ci	cancel_delayed_work_sync(&sfp->hwmon_probe);
160762306a36Sopenharmony_ci	if (!IS_ERR_OR_NULL(sfp->hwmon_dev)) {
160862306a36Sopenharmony_ci		hwmon_device_unregister(sfp->hwmon_dev);
160962306a36Sopenharmony_ci		sfp->hwmon_dev = NULL;
161062306a36Sopenharmony_ci		kfree(sfp->hwmon_name);
161162306a36Sopenharmony_ci	}
161262306a36Sopenharmony_ci}
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_cistatic int sfp_hwmon_init(struct sfp *sfp)
161562306a36Sopenharmony_ci{
161662306a36Sopenharmony_ci	INIT_DELAYED_WORK(&sfp->hwmon_probe, sfp_hwmon_probe);
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci	return 0;
161962306a36Sopenharmony_ci}
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_cistatic void sfp_hwmon_exit(struct sfp *sfp)
162262306a36Sopenharmony_ci{
162362306a36Sopenharmony_ci	cancel_delayed_work_sync(&sfp->hwmon_probe);
162462306a36Sopenharmony_ci}
162562306a36Sopenharmony_ci#else
162662306a36Sopenharmony_cistatic int sfp_hwmon_insert(struct sfp *sfp)
162762306a36Sopenharmony_ci{
162862306a36Sopenharmony_ci	return 0;
162962306a36Sopenharmony_ci}
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_cistatic void sfp_hwmon_remove(struct sfp *sfp)
163262306a36Sopenharmony_ci{
163362306a36Sopenharmony_ci}
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_cistatic int sfp_hwmon_init(struct sfp *sfp)
163662306a36Sopenharmony_ci{
163762306a36Sopenharmony_ci	return 0;
163862306a36Sopenharmony_ci}
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_cistatic void sfp_hwmon_exit(struct sfp *sfp)
164162306a36Sopenharmony_ci{
164262306a36Sopenharmony_ci}
164362306a36Sopenharmony_ci#endif
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci/* Helpers */
164662306a36Sopenharmony_cistatic void sfp_module_tx_disable(struct sfp *sfp)
164762306a36Sopenharmony_ci{
164862306a36Sopenharmony_ci	dev_dbg(sfp->dev, "tx disable %u -> %u\n",
164962306a36Sopenharmony_ci		sfp->state & SFP_F_TX_DISABLE ? 1 : 0, 1);
165062306a36Sopenharmony_ci	sfp_mod_state(sfp, SFP_F_TX_DISABLE, SFP_F_TX_DISABLE);
165162306a36Sopenharmony_ci}
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_cistatic void sfp_module_tx_enable(struct sfp *sfp)
165462306a36Sopenharmony_ci{
165562306a36Sopenharmony_ci	dev_dbg(sfp->dev, "tx disable %u -> %u\n",
165662306a36Sopenharmony_ci		sfp->state & SFP_F_TX_DISABLE ? 1 : 0, 0);
165762306a36Sopenharmony_ci	sfp_mod_state(sfp, SFP_F_TX_DISABLE, 0);
165862306a36Sopenharmony_ci}
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DEBUG_FS)
166162306a36Sopenharmony_cistatic int sfp_debug_state_show(struct seq_file *s, void *data)
166262306a36Sopenharmony_ci{
166362306a36Sopenharmony_ci	struct sfp *sfp = s->private;
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	seq_printf(s, "Module state: %s\n",
166662306a36Sopenharmony_ci		   mod_state_to_str(sfp->sm_mod_state));
166762306a36Sopenharmony_ci	seq_printf(s, "Module probe attempts: %d %d\n",
166862306a36Sopenharmony_ci		   R_PROBE_RETRY_INIT - sfp->sm_mod_tries_init,
166962306a36Sopenharmony_ci		   R_PROBE_RETRY_SLOW - sfp->sm_mod_tries);
167062306a36Sopenharmony_ci	seq_printf(s, "Device state: %s\n",
167162306a36Sopenharmony_ci		   dev_state_to_str(sfp->sm_dev_state));
167262306a36Sopenharmony_ci	seq_printf(s, "Main state: %s\n",
167362306a36Sopenharmony_ci		   sm_state_to_str(sfp->sm_state));
167462306a36Sopenharmony_ci	seq_printf(s, "Fault recovery remaining retries: %d\n",
167562306a36Sopenharmony_ci		   sfp->sm_fault_retries);
167662306a36Sopenharmony_ci	seq_printf(s, "PHY probe remaining retries: %d\n",
167762306a36Sopenharmony_ci		   sfp->sm_phy_retries);
167862306a36Sopenharmony_ci	seq_printf(s, "Signalling rate: %u kBd\n", sfp->rate_kbd);
167962306a36Sopenharmony_ci	seq_printf(s, "Rate select threshold: %u kBd\n",
168062306a36Sopenharmony_ci		   sfp->rs_threshold_kbd);
168162306a36Sopenharmony_ci	seq_printf(s, "moddef0: %d\n", !!(sfp->state & SFP_F_PRESENT));
168262306a36Sopenharmony_ci	seq_printf(s, "rx_los: %d\n", !!(sfp->state & SFP_F_LOS));
168362306a36Sopenharmony_ci	seq_printf(s, "tx_fault: %d\n", !!(sfp->state & SFP_F_TX_FAULT));
168462306a36Sopenharmony_ci	seq_printf(s, "tx_disable: %d\n", !!(sfp->state & SFP_F_TX_DISABLE));
168562306a36Sopenharmony_ci	seq_printf(s, "rs0: %d\n", !!(sfp->state & SFP_F_RS0));
168662306a36Sopenharmony_ci	seq_printf(s, "rs1: %d\n", !!(sfp->state & SFP_F_RS1));
168762306a36Sopenharmony_ci	return 0;
168862306a36Sopenharmony_ci}
168962306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(sfp_debug_state);
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_cistatic void sfp_debugfs_init(struct sfp *sfp)
169262306a36Sopenharmony_ci{
169362306a36Sopenharmony_ci	sfp->debugfs_dir = debugfs_create_dir(dev_name(sfp->dev), NULL);
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	debugfs_create_file("state", 0600, sfp->debugfs_dir, sfp,
169662306a36Sopenharmony_ci			    &sfp_debug_state_fops);
169762306a36Sopenharmony_ci}
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_cistatic void sfp_debugfs_exit(struct sfp *sfp)
170062306a36Sopenharmony_ci{
170162306a36Sopenharmony_ci	debugfs_remove_recursive(sfp->debugfs_dir);
170262306a36Sopenharmony_ci}
170362306a36Sopenharmony_ci#else
170462306a36Sopenharmony_cistatic void sfp_debugfs_init(struct sfp *sfp)
170562306a36Sopenharmony_ci{
170662306a36Sopenharmony_ci}
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_cistatic void sfp_debugfs_exit(struct sfp *sfp)
170962306a36Sopenharmony_ci{
171062306a36Sopenharmony_ci}
171162306a36Sopenharmony_ci#endif
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_cistatic void sfp_module_tx_fault_reset(struct sfp *sfp)
171462306a36Sopenharmony_ci{
171562306a36Sopenharmony_ci	unsigned int state;
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	mutex_lock(&sfp->st_mutex);
171862306a36Sopenharmony_ci	state = sfp->state;
171962306a36Sopenharmony_ci	if (!(state & SFP_F_TX_DISABLE)) {
172062306a36Sopenharmony_ci		sfp_set_state(sfp, state | SFP_F_TX_DISABLE);
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci		udelay(T_RESET_US);
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci		sfp_set_state(sfp, state);
172562306a36Sopenharmony_ci	}
172662306a36Sopenharmony_ci	mutex_unlock(&sfp->st_mutex);
172762306a36Sopenharmony_ci}
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci/* SFP state machine */
173062306a36Sopenharmony_cistatic void sfp_sm_set_timer(struct sfp *sfp, unsigned int timeout)
173162306a36Sopenharmony_ci{
173262306a36Sopenharmony_ci	if (timeout)
173362306a36Sopenharmony_ci		mod_delayed_work(system_power_efficient_wq, &sfp->timeout,
173462306a36Sopenharmony_ci				 timeout);
173562306a36Sopenharmony_ci	else
173662306a36Sopenharmony_ci		cancel_delayed_work(&sfp->timeout);
173762306a36Sopenharmony_ci}
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_cistatic void sfp_sm_next(struct sfp *sfp, unsigned int state,
174062306a36Sopenharmony_ci			unsigned int timeout)
174162306a36Sopenharmony_ci{
174262306a36Sopenharmony_ci	sfp->sm_state = state;
174362306a36Sopenharmony_ci	sfp_sm_set_timer(sfp, timeout);
174462306a36Sopenharmony_ci}
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_cistatic void sfp_sm_mod_next(struct sfp *sfp, unsigned int state,
174762306a36Sopenharmony_ci			    unsigned int timeout)
174862306a36Sopenharmony_ci{
174962306a36Sopenharmony_ci	sfp->sm_mod_state = state;
175062306a36Sopenharmony_ci	sfp_sm_set_timer(sfp, timeout);
175162306a36Sopenharmony_ci}
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_cistatic void sfp_sm_phy_detach(struct sfp *sfp)
175462306a36Sopenharmony_ci{
175562306a36Sopenharmony_ci	sfp_remove_phy(sfp->sfp_bus);
175662306a36Sopenharmony_ci	phy_device_remove(sfp->mod_phy);
175762306a36Sopenharmony_ci	phy_device_free(sfp->mod_phy);
175862306a36Sopenharmony_ci	sfp->mod_phy = NULL;
175962306a36Sopenharmony_ci}
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_cistatic int sfp_sm_probe_phy(struct sfp *sfp, int addr, bool is_c45)
176262306a36Sopenharmony_ci{
176362306a36Sopenharmony_ci	struct phy_device *phy;
176462306a36Sopenharmony_ci	int err;
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci	phy = get_phy_device(sfp->i2c_mii, addr, is_c45);
176762306a36Sopenharmony_ci	if (phy == ERR_PTR(-ENODEV))
176862306a36Sopenharmony_ci		return PTR_ERR(phy);
176962306a36Sopenharmony_ci	if (IS_ERR(phy)) {
177062306a36Sopenharmony_ci		dev_err(sfp->dev, "mdiobus scan returned %pe\n", phy);
177162306a36Sopenharmony_ci		return PTR_ERR(phy);
177262306a36Sopenharmony_ci	}
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	/* Mark this PHY as being on a SFP module */
177562306a36Sopenharmony_ci	phy->is_on_sfp_module = true;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	err = phy_device_register(phy);
177862306a36Sopenharmony_ci	if (err) {
177962306a36Sopenharmony_ci		phy_device_free(phy);
178062306a36Sopenharmony_ci		dev_err(sfp->dev, "phy_device_register failed: %pe\n",
178162306a36Sopenharmony_ci			ERR_PTR(err));
178262306a36Sopenharmony_ci		return err;
178362306a36Sopenharmony_ci	}
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	err = sfp_add_phy(sfp->sfp_bus, phy);
178662306a36Sopenharmony_ci	if (err) {
178762306a36Sopenharmony_ci		phy_device_remove(phy);
178862306a36Sopenharmony_ci		phy_device_free(phy);
178962306a36Sopenharmony_ci		dev_err(sfp->dev, "sfp_add_phy failed: %pe\n", ERR_PTR(err));
179062306a36Sopenharmony_ci		return err;
179162306a36Sopenharmony_ci	}
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	sfp->mod_phy = phy;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	return 0;
179662306a36Sopenharmony_ci}
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_cistatic void sfp_sm_link_up(struct sfp *sfp)
179962306a36Sopenharmony_ci{
180062306a36Sopenharmony_ci	sfp_link_up(sfp->sfp_bus);
180162306a36Sopenharmony_ci	sfp_sm_next(sfp, SFP_S_LINK_UP, 0);
180262306a36Sopenharmony_ci}
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_cistatic void sfp_sm_link_down(struct sfp *sfp)
180562306a36Sopenharmony_ci{
180662306a36Sopenharmony_ci	sfp_link_down(sfp->sfp_bus);
180762306a36Sopenharmony_ci}
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_cistatic void sfp_sm_link_check_los(struct sfp *sfp)
181062306a36Sopenharmony_ci{
181162306a36Sopenharmony_ci	const __be16 los_inverted = cpu_to_be16(SFP_OPTIONS_LOS_INVERTED);
181262306a36Sopenharmony_ci	const __be16 los_normal = cpu_to_be16(SFP_OPTIONS_LOS_NORMAL);
181362306a36Sopenharmony_ci	__be16 los_options = sfp->id.ext.options & (los_inverted | los_normal);
181462306a36Sopenharmony_ci	bool los = false;
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	/* If neither SFP_OPTIONS_LOS_INVERTED nor SFP_OPTIONS_LOS_NORMAL
181762306a36Sopenharmony_ci	 * are set, we assume that no LOS signal is available. If both are
181862306a36Sopenharmony_ci	 * set, we assume LOS is not implemented (and is meaningless.)
181962306a36Sopenharmony_ci	 */
182062306a36Sopenharmony_ci	if (los_options == los_inverted)
182162306a36Sopenharmony_ci		los = !(sfp->state & SFP_F_LOS);
182262306a36Sopenharmony_ci	else if (los_options == los_normal)
182362306a36Sopenharmony_ci		los = !!(sfp->state & SFP_F_LOS);
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	if (los)
182662306a36Sopenharmony_ci		sfp_sm_next(sfp, SFP_S_WAIT_LOS, 0);
182762306a36Sopenharmony_ci	else
182862306a36Sopenharmony_ci		sfp_sm_link_up(sfp);
182962306a36Sopenharmony_ci}
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_cistatic bool sfp_los_event_active(struct sfp *sfp, unsigned int event)
183262306a36Sopenharmony_ci{
183362306a36Sopenharmony_ci	const __be16 los_inverted = cpu_to_be16(SFP_OPTIONS_LOS_INVERTED);
183462306a36Sopenharmony_ci	const __be16 los_normal = cpu_to_be16(SFP_OPTIONS_LOS_NORMAL);
183562306a36Sopenharmony_ci	__be16 los_options = sfp->id.ext.options & (los_inverted | los_normal);
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	return (los_options == los_inverted && event == SFP_E_LOS_LOW) ||
183862306a36Sopenharmony_ci	       (los_options == los_normal && event == SFP_E_LOS_HIGH);
183962306a36Sopenharmony_ci}
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_cistatic bool sfp_los_event_inactive(struct sfp *sfp, unsigned int event)
184262306a36Sopenharmony_ci{
184362306a36Sopenharmony_ci	const __be16 los_inverted = cpu_to_be16(SFP_OPTIONS_LOS_INVERTED);
184462306a36Sopenharmony_ci	const __be16 los_normal = cpu_to_be16(SFP_OPTIONS_LOS_NORMAL);
184562306a36Sopenharmony_ci	__be16 los_options = sfp->id.ext.options & (los_inverted | los_normal);
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	return (los_options == los_inverted && event == SFP_E_LOS_HIGH) ||
184862306a36Sopenharmony_ci	       (los_options == los_normal && event == SFP_E_LOS_LOW);
184962306a36Sopenharmony_ci}
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_cistatic void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn)
185262306a36Sopenharmony_ci{
185362306a36Sopenharmony_ci	if (sfp->sm_fault_retries && !--sfp->sm_fault_retries) {
185462306a36Sopenharmony_ci		dev_err(sfp->dev,
185562306a36Sopenharmony_ci			"module persistently indicates fault, disabling\n");
185662306a36Sopenharmony_ci		sfp_sm_next(sfp, SFP_S_TX_DISABLE, 0);
185762306a36Sopenharmony_ci	} else {
185862306a36Sopenharmony_ci		if (warn)
185962306a36Sopenharmony_ci			dev_err(sfp->dev, "module transmit fault indicated\n");
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci		sfp_sm_next(sfp, next_state, T_FAULT_RECOVER);
186262306a36Sopenharmony_ci	}
186362306a36Sopenharmony_ci}
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_cistatic int sfp_sm_add_mdio_bus(struct sfp *sfp)
186662306a36Sopenharmony_ci{
186762306a36Sopenharmony_ci	if (sfp->mdio_protocol != MDIO_I2C_NONE)
186862306a36Sopenharmony_ci		return sfp_i2c_mdiobus_create(sfp);
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	return 0;
187162306a36Sopenharmony_ci}
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci/* Probe a SFP for a PHY device if the module supports copper - the PHY
187462306a36Sopenharmony_ci * normally sits at I2C bus address 0x56, and may either be a clause 22
187562306a36Sopenharmony_ci * or clause 45 PHY.
187662306a36Sopenharmony_ci *
187762306a36Sopenharmony_ci * Clause 22 copper SFP modules normally operate in Cisco SGMII mode with
187862306a36Sopenharmony_ci * negotiation enabled, but some may be in 1000base-X - which is for the
187962306a36Sopenharmony_ci * PHY driver to determine.
188062306a36Sopenharmony_ci *
188162306a36Sopenharmony_ci * Clause 45 copper SFP+ modules (10G) appear to switch their interface
188262306a36Sopenharmony_ci * mode according to the negotiated line speed.
188362306a36Sopenharmony_ci */
188462306a36Sopenharmony_cistatic int sfp_sm_probe_for_phy(struct sfp *sfp)
188562306a36Sopenharmony_ci{
188662306a36Sopenharmony_ci	int err = 0;
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci	switch (sfp->mdio_protocol) {
188962306a36Sopenharmony_ci	case MDIO_I2C_NONE:
189062306a36Sopenharmony_ci		break;
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	case MDIO_I2C_MARVELL_C22:
189362306a36Sopenharmony_ci		err = sfp_sm_probe_phy(sfp, SFP_PHY_ADDR, false);
189462306a36Sopenharmony_ci		break;
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	case MDIO_I2C_C45:
189762306a36Sopenharmony_ci		err = sfp_sm_probe_phy(sfp, SFP_PHY_ADDR, true);
189862306a36Sopenharmony_ci		break;
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	case MDIO_I2C_ROLLBALL:
190162306a36Sopenharmony_ci		err = sfp_sm_probe_phy(sfp, SFP_PHY_ADDR_ROLLBALL, true);
190262306a36Sopenharmony_ci		break;
190362306a36Sopenharmony_ci	}
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	return err;
190662306a36Sopenharmony_ci}
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_cistatic int sfp_module_parse_power(struct sfp *sfp)
190962306a36Sopenharmony_ci{
191062306a36Sopenharmony_ci	u32 power_mW = 1000;
191162306a36Sopenharmony_ci	bool supports_a2;
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	if (sfp->id.ext.sff8472_compliance >= SFP_SFF8472_COMPLIANCE_REV10_2 &&
191462306a36Sopenharmony_ci	    sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_POWER_DECL))
191562306a36Sopenharmony_ci		power_mW = 1500;
191662306a36Sopenharmony_ci	/* Added in Rev 11.9, but there is no compliance code for this */
191762306a36Sopenharmony_ci	if (sfp->id.ext.sff8472_compliance >= SFP_SFF8472_COMPLIANCE_REV11_4 &&
191862306a36Sopenharmony_ci	    sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL))
191962306a36Sopenharmony_ci		power_mW = 2000;
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	/* Power level 1 modules (max. 1W) are always supported. */
192262306a36Sopenharmony_ci	if (power_mW <= 1000) {
192362306a36Sopenharmony_ci		sfp->module_power_mW = power_mW;
192462306a36Sopenharmony_ci		return 0;
192562306a36Sopenharmony_ci	}
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	supports_a2 = sfp->id.ext.sff8472_compliance !=
192862306a36Sopenharmony_ci				SFP_SFF8472_COMPLIANCE_NONE ||
192962306a36Sopenharmony_ci		      sfp->id.ext.diagmon & SFP_DIAGMON_DDM;
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci	if (power_mW > sfp->max_power_mW) {
193262306a36Sopenharmony_ci		/* Module power specification exceeds the allowed maximum. */
193362306a36Sopenharmony_ci		if (!supports_a2) {
193462306a36Sopenharmony_ci			/* The module appears not to implement bus address
193562306a36Sopenharmony_ci			 * 0xa2, so assume that the module powers up in the
193662306a36Sopenharmony_ci			 * indicated mode.
193762306a36Sopenharmony_ci			 */
193862306a36Sopenharmony_ci			dev_err(sfp->dev,
193962306a36Sopenharmony_ci				"Host does not support %u.%uW modules\n",
194062306a36Sopenharmony_ci				power_mW / 1000, (power_mW / 100) % 10);
194162306a36Sopenharmony_ci			return -EINVAL;
194262306a36Sopenharmony_ci		} else {
194362306a36Sopenharmony_ci			dev_warn(sfp->dev,
194462306a36Sopenharmony_ci				 "Host does not support %u.%uW modules, module left in power mode 1\n",
194562306a36Sopenharmony_ci				 power_mW / 1000, (power_mW / 100) % 10);
194662306a36Sopenharmony_ci			return 0;
194762306a36Sopenharmony_ci		}
194862306a36Sopenharmony_ci	}
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci	if (!supports_a2) {
195162306a36Sopenharmony_ci		/* The module power level is below the host maximum and the
195262306a36Sopenharmony_ci		 * module appears not to implement bus address 0xa2, so assume
195362306a36Sopenharmony_ci		 * that the module powers up in the indicated mode.
195462306a36Sopenharmony_ci		 */
195562306a36Sopenharmony_ci		return 0;
195662306a36Sopenharmony_ci	}
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	/* If the module requires a higher power mode, but also requires
195962306a36Sopenharmony_ci	 * an address change sequence, warn the user that the module may
196062306a36Sopenharmony_ci	 * not be functional.
196162306a36Sopenharmony_ci	 */
196262306a36Sopenharmony_ci	if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE) {
196362306a36Sopenharmony_ci		dev_warn(sfp->dev,
196462306a36Sopenharmony_ci			 "Address Change Sequence not supported but module requires %u.%uW, module may not be functional\n",
196562306a36Sopenharmony_ci			 power_mW / 1000, (power_mW / 100) % 10);
196662306a36Sopenharmony_ci		return 0;
196762306a36Sopenharmony_ci	}
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci	sfp->module_power_mW = power_mW;
197062306a36Sopenharmony_ci
197162306a36Sopenharmony_ci	return 0;
197262306a36Sopenharmony_ci}
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_cistatic int sfp_sm_mod_hpower(struct sfp *sfp, bool enable)
197562306a36Sopenharmony_ci{
197662306a36Sopenharmony_ci	int err;
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	err = sfp_modify_u8(sfp, true, SFP_EXT_STATUS,
197962306a36Sopenharmony_ci			    SFP_EXT_STATUS_PWRLVL_SELECT,
198062306a36Sopenharmony_ci			    enable ? SFP_EXT_STATUS_PWRLVL_SELECT : 0);
198162306a36Sopenharmony_ci	if (err != sizeof(u8)) {
198262306a36Sopenharmony_ci		dev_err(sfp->dev, "failed to %sable high power: %pe\n",
198362306a36Sopenharmony_ci			enable ? "en" : "dis", ERR_PTR(err));
198462306a36Sopenharmony_ci		return -EAGAIN;
198562306a36Sopenharmony_ci	}
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci	if (enable)
198862306a36Sopenharmony_ci		dev_info(sfp->dev, "Module switched to %u.%uW power level\n",
198962306a36Sopenharmony_ci			 sfp->module_power_mW / 1000,
199062306a36Sopenharmony_ci			 (sfp->module_power_mW / 100) % 10);
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	return 0;
199362306a36Sopenharmony_ci}
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_cistatic void sfp_module_parse_rate_select(struct sfp *sfp)
199662306a36Sopenharmony_ci{
199762306a36Sopenharmony_ci	u8 rate_id;
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	sfp->rs_threshold_kbd = 0;
200062306a36Sopenharmony_ci	sfp->rs_state_mask = 0;
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	if (!(sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_RATE_SELECT)))
200362306a36Sopenharmony_ci		/* No support for RateSelect */
200462306a36Sopenharmony_ci		return;
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	/* Default to INF-8074 RateSelect operation. The signalling threshold
200762306a36Sopenharmony_ci	 * rate is not well specified, so always select "Full Bandwidth", but
200862306a36Sopenharmony_ci	 * SFF-8079 reveals that it is understood that RS0 will be low for
200962306a36Sopenharmony_ci	 * 1.0625Gb/s and high for 2.125Gb/s. Choose a value half-way between.
201062306a36Sopenharmony_ci	 * This method exists prior to SFF-8472.
201162306a36Sopenharmony_ci	 */
201262306a36Sopenharmony_ci	sfp->rs_state_mask = SFP_F_RS0;
201362306a36Sopenharmony_ci	sfp->rs_threshold_kbd = 1594;
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	/* Parse the rate identifier, which is complicated due to history:
201662306a36Sopenharmony_ci	 * SFF-8472 rev 9.5 marks this field as reserved.
201762306a36Sopenharmony_ci	 * SFF-8079 references SFF-8472 rev 9.5 and defines bit 0. SFF-8472
201862306a36Sopenharmony_ci	 *  compliance is not required.
201962306a36Sopenharmony_ci	 * SFF-8472 rev 10.2 defines this field using values 0..4
202062306a36Sopenharmony_ci	 * SFF-8472 rev 11.0 redefines this field with bit 0 for SFF-8079
202162306a36Sopenharmony_ci	 * and even values.
202262306a36Sopenharmony_ci	 */
202362306a36Sopenharmony_ci	rate_id = sfp->id.base.rate_id;
202462306a36Sopenharmony_ci	if (rate_id == 0)
202562306a36Sopenharmony_ci		/* Unspecified */
202662306a36Sopenharmony_ci		return;
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	/* SFF-8472 rev 10.0..10.4 did not account for SFF-8079 using bit 0,
202962306a36Sopenharmony_ci	 * and allocated value 3 to SFF-8431 independent tx/rx rate select.
203062306a36Sopenharmony_ci	 * Convert this to a SFF-8472 rev 11.0 rate identifier.
203162306a36Sopenharmony_ci	 */
203262306a36Sopenharmony_ci	if (sfp->id.ext.sff8472_compliance >= SFP_SFF8472_COMPLIANCE_REV10_2 &&
203362306a36Sopenharmony_ci	    sfp->id.ext.sff8472_compliance < SFP_SFF8472_COMPLIANCE_REV11_0 &&
203462306a36Sopenharmony_ci	    rate_id == 3)
203562306a36Sopenharmony_ci		rate_id = SFF_RID_8431;
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	if (rate_id & SFF_RID_8079) {
203862306a36Sopenharmony_ci		/* SFF-8079 RateSelect / Application Select in conjunction with
203962306a36Sopenharmony_ci		 * SFF-8472 rev 9.5. SFF-8079 defines rate_id as a bitfield
204062306a36Sopenharmony_ci		 * with only bit 0 used, which takes precedence over SFF-8472.
204162306a36Sopenharmony_ci		 */
204262306a36Sopenharmony_ci		if (!(sfp->id.ext.enhopts & SFP_ENHOPTS_APP_SELECT_SFF8079)) {
204362306a36Sopenharmony_ci			/* SFF-8079 Part 1 - rate selection between Fibre
204462306a36Sopenharmony_ci			 * Channel 1.0625/2.125/4.25 Gbd modes. Note that RS0
204562306a36Sopenharmony_ci			 * is high for 2125, so we have to subtract 1 to
204662306a36Sopenharmony_ci			 * include it.
204762306a36Sopenharmony_ci			 */
204862306a36Sopenharmony_ci			sfp->rs_threshold_kbd = 2125 - 1;
204962306a36Sopenharmony_ci			sfp->rs_state_mask = SFP_F_RS0;
205062306a36Sopenharmony_ci		}
205162306a36Sopenharmony_ci		return;
205262306a36Sopenharmony_ci	}
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ci	/* SFF-8472 rev 9.5 does not define the rate identifier */
205562306a36Sopenharmony_ci	if (sfp->id.ext.sff8472_compliance <= SFP_SFF8472_COMPLIANCE_REV9_5)
205662306a36Sopenharmony_ci		return;
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci	/* SFF-8472 rev 11.0 defines rate_id as a numerical value which will
205962306a36Sopenharmony_ci	 * always have bit 0 clear due to SFF-8079's bitfield usage of rate_id.
206062306a36Sopenharmony_ci	 */
206162306a36Sopenharmony_ci	switch (rate_id) {
206262306a36Sopenharmony_ci	case SFF_RID_8431_RX_ONLY:
206362306a36Sopenharmony_ci		sfp->rs_threshold_kbd = 4250;
206462306a36Sopenharmony_ci		sfp->rs_state_mask = SFP_F_RS0;
206562306a36Sopenharmony_ci		break;
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci	case SFF_RID_8431_TX_ONLY:
206862306a36Sopenharmony_ci		sfp->rs_threshold_kbd = 4250;
206962306a36Sopenharmony_ci		sfp->rs_state_mask = SFP_F_RS1;
207062306a36Sopenharmony_ci		break;
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci	case SFF_RID_8431:
207362306a36Sopenharmony_ci		sfp->rs_threshold_kbd = 4250;
207462306a36Sopenharmony_ci		sfp->rs_state_mask = SFP_F_RS0 | SFP_F_RS1;
207562306a36Sopenharmony_ci		break;
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	case SFF_RID_10G8G:
207862306a36Sopenharmony_ci		sfp->rs_threshold_kbd = 9000;
207962306a36Sopenharmony_ci		sfp->rs_state_mask = SFP_F_RS0 | SFP_F_RS1;
208062306a36Sopenharmony_ci		break;
208162306a36Sopenharmony_ci	}
208262306a36Sopenharmony_ci}
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci/* GPON modules based on Realtek RTL8672 and RTL9601C chips (e.g. V-SOL
208562306a36Sopenharmony_ci * V2801F, CarlitoxxPro CPGOS03-0490, Ubiquiti U-Fiber Instant, ...) do
208662306a36Sopenharmony_ci * not support multibyte reads from the EEPROM. Each multi-byte read
208762306a36Sopenharmony_ci * operation returns just one byte of EEPROM followed by zeros. There is
208862306a36Sopenharmony_ci * no way to identify which modules are using Realtek RTL8672 and RTL9601C
208962306a36Sopenharmony_ci * chips. Moreover every OEM of V-SOL V2801F module puts its own vendor
209062306a36Sopenharmony_ci * name and vendor id into EEPROM, so there is even no way to detect if
209162306a36Sopenharmony_ci * module is V-SOL V2801F. Therefore check for those zeros in the read
209262306a36Sopenharmony_ci * data and then based on check switch to reading EEPROM to one byte
209362306a36Sopenharmony_ci * at a time.
209462306a36Sopenharmony_ci */
209562306a36Sopenharmony_cistatic bool sfp_id_needs_byte_io(struct sfp *sfp, void *buf, size_t len)
209662306a36Sopenharmony_ci{
209762306a36Sopenharmony_ci	size_t i, block_size = sfp->i2c_block_size;
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci	/* Already using byte IO */
210062306a36Sopenharmony_ci	if (block_size == 1)
210162306a36Sopenharmony_ci		return false;
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci	for (i = 1; i < len; i += block_size) {
210462306a36Sopenharmony_ci		if (memchr_inv(buf + i, '\0', min(block_size - 1, len - i)))
210562306a36Sopenharmony_ci			return false;
210662306a36Sopenharmony_ci	}
210762306a36Sopenharmony_ci	return true;
210862306a36Sopenharmony_ci}
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_cistatic int sfp_cotsworks_fixup_check(struct sfp *sfp, struct sfp_eeprom_id *id)
211162306a36Sopenharmony_ci{
211262306a36Sopenharmony_ci	u8 check;
211362306a36Sopenharmony_ci	int err;
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	if (id->base.phys_id != SFF8024_ID_SFF_8472 ||
211662306a36Sopenharmony_ci	    id->base.phys_ext_id != SFP_PHYS_EXT_ID_SFP ||
211762306a36Sopenharmony_ci	    id->base.connector != SFF8024_CONNECTOR_LC) {
211862306a36Sopenharmony_ci		dev_warn(sfp->dev, "Rewriting fiber module EEPROM with corrected values\n");
211962306a36Sopenharmony_ci		id->base.phys_id = SFF8024_ID_SFF_8472;
212062306a36Sopenharmony_ci		id->base.phys_ext_id = SFP_PHYS_EXT_ID_SFP;
212162306a36Sopenharmony_ci		id->base.connector = SFF8024_CONNECTOR_LC;
212262306a36Sopenharmony_ci		err = sfp_write(sfp, false, SFP_PHYS_ID, &id->base, 3);
212362306a36Sopenharmony_ci		if (err != 3) {
212462306a36Sopenharmony_ci			dev_err(sfp->dev,
212562306a36Sopenharmony_ci				"Failed to rewrite module EEPROM: %pe\n",
212662306a36Sopenharmony_ci				ERR_PTR(err));
212762306a36Sopenharmony_ci			return err;
212862306a36Sopenharmony_ci		}
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci		/* Cotsworks modules have been found to require a delay between write operations. */
213162306a36Sopenharmony_ci		mdelay(50);
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci		/* Update base structure checksum */
213462306a36Sopenharmony_ci		check = sfp_check(&id->base, sizeof(id->base) - 1);
213562306a36Sopenharmony_ci		err = sfp_write(sfp, false, SFP_CC_BASE, &check, 1);
213662306a36Sopenharmony_ci		if (err != 1) {
213762306a36Sopenharmony_ci			dev_err(sfp->dev,
213862306a36Sopenharmony_ci				"Failed to update base structure checksum in fiber module EEPROM: %pe\n",
213962306a36Sopenharmony_ci				ERR_PTR(err));
214062306a36Sopenharmony_ci			return err;
214162306a36Sopenharmony_ci		}
214262306a36Sopenharmony_ci	}
214362306a36Sopenharmony_ci	return 0;
214462306a36Sopenharmony_ci}
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_cistatic int sfp_module_parse_sff8472(struct sfp *sfp)
214762306a36Sopenharmony_ci{
214862306a36Sopenharmony_ci	/* If the module requires address swap mode, warn about it */
214962306a36Sopenharmony_ci	if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE)
215062306a36Sopenharmony_ci		dev_warn(sfp->dev,
215162306a36Sopenharmony_ci			 "module address swap to access page 0xA2 is not supported.\n");
215262306a36Sopenharmony_ci	else
215362306a36Sopenharmony_ci		sfp->have_a2 = true;
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci	return 0;
215662306a36Sopenharmony_ci}
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_cistatic int sfp_sm_mod_probe(struct sfp *sfp, bool report)
215962306a36Sopenharmony_ci{
216062306a36Sopenharmony_ci	/* SFP module inserted - read I2C data */
216162306a36Sopenharmony_ci	struct sfp_eeprom_id id;
216262306a36Sopenharmony_ci	bool cotsworks_sfbg;
216362306a36Sopenharmony_ci	unsigned int mask;
216462306a36Sopenharmony_ci	bool cotsworks;
216562306a36Sopenharmony_ci	u8 check;
216662306a36Sopenharmony_ci	int ret;
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci	sfp->i2c_block_size = SFP_EEPROM_BLOCK_SIZE;
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ci	ret = sfp_read(sfp, false, 0, &id.base, sizeof(id.base));
217162306a36Sopenharmony_ci	if (ret < 0) {
217262306a36Sopenharmony_ci		if (report)
217362306a36Sopenharmony_ci			dev_err(sfp->dev, "failed to read EEPROM: %pe\n",
217462306a36Sopenharmony_ci				ERR_PTR(ret));
217562306a36Sopenharmony_ci		return -EAGAIN;
217662306a36Sopenharmony_ci	}
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_ci	if (ret != sizeof(id.base)) {
217962306a36Sopenharmony_ci		dev_err(sfp->dev, "EEPROM short read: %pe\n", ERR_PTR(ret));
218062306a36Sopenharmony_ci		return -EAGAIN;
218162306a36Sopenharmony_ci	}
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci	/* Some SFP modules (e.g. Nokia 3FE46541AA) lock up if read from
218462306a36Sopenharmony_ci	 * address 0x51 is just one byte at a time. Also SFF-8472 requires
218562306a36Sopenharmony_ci	 * that EEPROM supports atomic 16bit read operation for diagnostic
218662306a36Sopenharmony_ci	 * fields, so do not switch to one byte reading at a time unless it
218762306a36Sopenharmony_ci	 * is really required and we have no other option.
218862306a36Sopenharmony_ci	 */
218962306a36Sopenharmony_ci	if (sfp_id_needs_byte_io(sfp, &id.base, sizeof(id.base))) {
219062306a36Sopenharmony_ci		dev_info(sfp->dev,
219162306a36Sopenharmony_ci			 "Detected broken RTL8672/RTL9601C emulated EEPROM\n");
219262306a36Sopenharmony_ci		dev_info(sfp->dev,
219362306a36Sopenharmony_ci			 "Switching to reading EEPROM to one byte at a time\n");
219462306a36Sopenharmony_ci		sfp->i2c_block_size = 1;
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci		ret = sfp_read(sfp, false, 0, &id.base, sizeof(id.base));
219762306a36Sopenharmony_ci		if (ret < 0) {
219862306a36Sopenharmony_ci			if (report)
219962306a36Sopenharmony_ci				dev_err(sfp->dev,
220062306a36Sopenharmony_ci					"failed to read EEPROM: %pe\n",
220162306a36Sopenharmony_ci					ERR_PTR(ret));
220262306a36Sopenharmony_ci			return -EAGAIN;
220362306a36Sopenharmony_ci		}
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci		if (ret != sizeof(id.base)) {
220662306a36Sopenharmony_ci			dev_err(sfp->dev, "EEPROM short read: %pe\n",
220762306a36Sopenharmony_ci				ERR_PTR(ret));
220862306a36Sopenharmony_ci			return -EAGAIN;
220962306a36Sopenharmony_ci		}
221062306a36Sopenharmony_ci	}
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci	/* Cotsworks do not seem to update the checksums when they
221362306a36Sopenharmony_ci	 * do the final programming with the final module part number,
221462306a36Sopenharmony_ci	 * serial number and date code.
221562306a36Sopenharmony_ci	 */
221662306a36Sopenharmony_ci	cotsworks = !memcmp(id.base.vendor_name, "COTSWORKS       ", 16);
221762306a36Sopenharmony_ci	cotsworks_sfbg = !memcmp(id.base.vendor_pn, "SFBG", 4);
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	/* Cotsworks SFF module EEPROM do not always have valid phys_id,
222062306a36Sopenharmony_ci	 * phys_ext_id, and connector bytes.  Rewrite SFF EEPROM bytes if
222162306a36Sopenharmony_ci	 * Cotsworks PN matches and bytes are not correct.
222262306a36Sopenharmony_ci	 */
222362306a36Sopenharmony_ci	if (cotsworks && cotsworks_sfbg) {
222462306a36Sopenharmony_ci		ret = sfp_cotsworks_fixup_check(sfp, &id);
222562306a36Sopenharmony_ci		if (ret < 0)
222662306a36Sopenharmony_ci			return ret;
222762306a36Sopenharmony_ci	}
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_ci	/* Validate the checksum over the base structure */
223062306a36Sopenharmony_ci	check = sfp_check(&id.base, sizeof(id.base) - 1);
223162306a36Sopenharmony_ci	if (check != id.base.cc_base) {
223262306a36Sopenharmony_ci		if (cotsworks) {
223362306a36Sopenharmony_ci			dev_warn(sfp->dev,
223462306a36Sopenharmony_ci				 "EEPROM base structure checksum failure (0x%02x != 0x%02x)\n",
223562306a36Sopenharmony_ci				 check, id.base.cc_base);
223662306a36Sopenharmony_ci		} else {
223762306a36Sopenharmony_ci			dev_err(sfp->dev,
223862306a36Sopenharmony_ci				"EEPROM base structure checksum failure: 0x%02x != 0x%02x\n",
223962306a36Sopenharmony_ci				check, id.base.cc_base);
224062306a36Sopenharmony_ci			print_hex_dump(KERN_ERR, "sfp EE: ", DUMP_PREFIX_OFFSET,
224162306a36Sopenharmony_ci				       16, 1, &id, sizeof(id), true);
224262306a36Sopenharmony_ci			return -EINVAL;
224362306a36Sopenharmony_ci		}
224462306a36Sopenharmony_ci	}
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	ret = sfp_read(sfp, false, SFP_CC_BASE + 1, &id.ext, sizeof(id.ext));
224762306a36Sopenharmony_ci	if (ret < 0) {
224862306a36Sopenharmony_ci		if (report)
224962306a36Sopenharmony_ci			dev_err(sfp->dev, "failed to read EEPROM: %pe\n",
225062306a36Sopenharmony_ci				ERR_PTR(ret));
225162306a36Sopenharmony_ci		return -EAGAIN;
225262306a36Sopenharmony_ci	}
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci	if (ret != sizeof(id.ext)) {
225562306a36Sopenharmony_ci		dev_err(sfp->dev, "EEPROM short read: %pe\n", ERR_PTR(ret));
225662306a36Sopenharmony_ci		return -EAGAIN;
225762306a36Sopenharmony_ci	}
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci	check = sfp_check(&id.ext, sizeof(id.ext) - 1);
226062306a36Sopenharmony_ci	if (check != id.ext.cc_ext) {
226162306a36Sopenharmony_ci		if (cotsworks) {
226262306a36Sopenharmony_ci			dev_warn(sfp->dev,
226362306a36Sopenharmony_ci				 "EEPROM extended structure checksum failure (0x%02x != 0x%02x)\n",
226462306a36Sopenharmony_ci				 check, id.ext.cc_ext);
226562306a36Sopenharmony_ci		} else {
226662306a36Sopenharmony_ci			dev_err(sfp->dev,
226762306a36Sopenharmony_ci				"EEPROM extended structure checksum failure: 0x%02x != 0x%02x\n",
226862306a36Sopenharmony_ci				check, id.ext.cc_ext);
226962306a36Sopenharmony_ci			print_hex_dump(KERN_ERR, "sfp EE: ", DUMP_PREFIX_OFFSET,
227062306a36Sopenharmony_ci				       16, 1, &id, sizeof(id), true);
227162306a36Sopenharmony_ci			memset(&id.ext, 0, sizeof(id.ext));
227262306a36Sopenharmony_ci		}
227362306a36Sopenharmony_ci	}
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci	sfp->id = id;
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	dev_info(sfp->dev, "module %.*s %.*s rev %.*s sn %.*s dc %.*s\n",
227862306a36Sopenharmony_ci		 (int)sizeof(id.base.vendor_name), id.base.vendor_name,
227962306a36Sopenharmony_ci		 (int)sizeof(id.base.vendor_pn), id.base.vendor_pn,
228062306a36Sopenharmony_ci		 (int)sizeof(id.base.vendor_rev), id.base.vendor_rev,
228162306a36Sopenharmony_ci		 (int)sizeof(id.ext.vendor_sn), id.ext.vendor_sn,
228262306a36Sopenharmony_ci		 (int)sizeof(id.ext.datecode), id.ext.datecode);
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci	/* Check whether we support this module */
228562306a36Sopenharmony_ci	if (!sfp->type->module_supported(&id)) {
228662306a36Sopenharmony_ci		dev_err(sfp->dev,
228762306a36Sopenharmony_ci			"module is not supported - phys id 0x%02x 0x%02x\n",
228862306a36Sopenharmony_ci			sfp->id.base.phys_id, sfp->id.base.phys_ext_id);
228962306a36Sopenharmony_ci		return -EINVAL;
229062306a36Sopenharmony_ci	}
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	if (sfp->id.ext.sff8472_compliance != SFP_SFF8472_COMPLIANCE_NONE) {
229362306a36Sopenharmony_ci		ret = sfp_module_parse_sff8472(sfp);
229462306a36Sopenharmony_ci		if (ret < 0)
229562306a36Sopenharmony_ci			return ret;
229662306a36Sopenharmony_ci	}
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci	/* Parse the module power requirement */
229962306a36Sopenharmony_ci	ret = sfp_module_parse_power(sfp);
230062306a36Sopenharmony_ci	if (ret < 0)
230162306a36Sopenharmony_ci		return ret;
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	sfp_module_parse_rate_select(sfp);
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci	mask = SFP_F_PRESENT;
230662306a36Sopenharmony_ci	if (sfp->gpio[GPIO_TX_DISABLE])
230762306a36Sopenharmony_ci		mask |= SFP_F_TX_DISABLE;
230862306a36Sopenharmony_ci	if (sfp->gpio[GPIO_TX_FAULT])
230962306a36Sopenharmony_ci		mask |= SFP_F_TX_FAULT;
231062306a36Sopenharmony_ci	if (sfp->gpio[GPIO_LOS])
231162306a36Sopenharmony_ci		mask |= SFP_F_LOS;
231262306a36Sopenharmony_ci	if (sfp->gpio[GPIO_RS0])
231362306a36Sopenharmony_ci		mask |= SFP_F_RS0;
231462306a36Sopenharmony_ci	if (sfp->gpio[GPIO_RS1])
231562306a36Sopenharmony_ci		mask |= SFP_F_RS1;
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci	sfp->module_t_start_up = T_START_UP;
231862306a36Sopenharmony_ci	sfp->module_t_wait = T_WAIT;
231962306a36Sopenharmony_ci
232062306a36Sopenharmony_ci	sfp->tx_fault_ignore = false;
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	if (sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SFI ||
232362306a36Sopenharmony_ci	    sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SR ||
232462306a36Sopenharmony_ci	    sfp->id.base.extended_cc == SFF8024_ECC_5GBASE_T ||
232562306a36Sopenharmony_ci	    sfp->id.base.extended_cc == SFF8024_ECC_2_5GBASE_T)
232662306a36Sopenharmony_ci		sfp->mdio_protocol = MDIO_I2C_C45;
232762306a36Sopenharmony_ci	else if (sfp->id.base.e1000_base_t)
232862306a36Sopenharmony_ci		sfp->mdio_protocol = MDIO_I2C_MARVELL_C22;
232962306a36Sopenharmony_ci	else
233062306a36Sopenharmony_ci		sfp->mdio_protocol = MDIO_I2C_NONE;
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci	sfp->quirk = sfp_lookup_quirk(&id);
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci	mutex_lock(&sfp->st_mutex);
233562306a36Sopenharmony_ci	/* Initialise state bits to use from hardware */
233662306a36Sopenharmony_ci	sfp->state_hw_mask = mask;
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_ci	/* We want to drive the rate select pins that the module is using */
233962306a36Sopenharmony_ci	sfp->state_hw_drive |= sfp->rs_state_mask;
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_ci	if (sfp->quirk && sfp->quirk->fixup)
234262306a36Sopenharmony_ci		sfp->quirk->fixup(sfp);
234362306a36Sopenharmony_ci	mutex_unlock(&sfp->st_mutex);
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci	return 0;
234662306a36Sopenharmony_ci}
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_cistatic void sfp_sm_mod_remove(struct sfp *sfp)
234962306a36Sopenharmony_ci{
235062306a36Sopenharmony_ci	if (sfp->sm_mod_state > SFP_MOD_WAITDEV)
235162306a36Sopenharmony_ci		sfp_module_remove(sfp->sfp_bus);
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_ci	sfp_hwmon_remove(sfp);
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_ci	memset(&sfp->id, 0, sizeof(sfp->id));
235662306a36Sopenharmony_ci	sfp->module_power_mW = 0;
235762306a36Sopenharmony_ci	sfp->state_hw_drive = SFP_F_TX_DISABLE;
235862306a36Sopenharmony_ci	sfp->have_a2 = false;
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ci	dev_info(sfp->dev, "module removed\n");
236162306a36Sopenharmony_ci}
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci/* This state machine tracks the upstream's state */
236462306a36Sopenharmony_cistatic void sfp_sm_device(struct sfp *sfp, unsigned int event)
236562306a36Sopenharmony_ci{
236662306a36Sopenharmony_ci	switch (sfp->sm_dev_state) {
236762306a36Sopenharmony_ci	default:
236862306a36Sopenharmony_ci		if (event == SFP_E_DEV_ATTACH)
236962306a36Sopenharmony_ci			sfp->sm_dev_state = SFP_DEV_DOWN;
237062306a36Sopenharmony_ci		break;
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci	case SFP_DEV_DOWN:
237362306a36Sopenharmony_ci		if (event == SFP_E_DEV_DETACH)
237462306a36Sopenharmony_ci			sfp->sm_dev_state = SFP_DEV_DETACHED;
237562306a36Sopenharmony_ci		else if (event == SFP_E_DEV_UP)
237662306a36Sopenharmony_ci			sfp->sm_dev_state = SFP_DEV_UP;
237762306a36Sopenharmony_ci		break;
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci	case SFP_DEV_UP:
238062306a36Sopenharmony_ci		if (event == SFP_E_DEV_DETACH)
238162306a36Sopenharmony_ci			sfp->sm_dev_state = SFP_DEV_DETACHED;
238262306a36Sopenharmony_ci		else if (event == SFP_E_DEV_DOWN)
238362306a36Sopenharmony_ci			sfp->sm_dev_state = SFP_DEV_DOWN;
238462306a36Sopenharmony_ci		break;
238562306a36Sopenharmony_ci	}
238662306a36Sopenharmony_ci}
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_ci/* This state machine tracks the insert/remove state of the module, probes
238962306a36Sopenharmony_ci * the on-board EEPROM, and sets up the power level.
239062306a36Sopenharmony_ci */
239162306a36Sopenharmony_cistatic void sfp_sm_module(struct sfp *sfp, unsigned int event)
239262306a36Sopenharmony_ci{
239362306a36Sopenharmony_ci	int err;
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_ci	/* Handle remove event globally, it resets this state machine */
239662306a36Sopenharmony_ci	if (event == SFP_E_REMOVE) {
239762306a36Sopenharmony_ci		if (sfp->sm_mod_state > SFP_MOD_PROBE)
239862306a36Sopenharmony_ci			sfp_sm_mod_remove(sfp);
239962306a36Sopenharmony_ci		sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
240062306a36Sopenharmony_ci		return;
240162306a36Sopenharmony_ci	}
240262306a36Sopenharmony_ci
240362306a36Sopenharmony_ci	/* Handle device detach globally */
240462306a36Sopenharmony_ci	if (sfp->sm_dev_state < SFP_DEV_DOWN &&
240562306a36Sopenharmony_ci	    sfp->sm_mod_state > SFP_MOD_WAITDEV) {
240662306a36Sopenharmony_ci		if (sfp->module_power_mW > 1000 &&
240762306a36Sopenharmony_ci		    sfp->sm_mod_state > SFP_MOD_HPOWER)
240862306a36Sopenharmony_ci			sfp_sm_mod_hpower(sfp, false);
240962306a36Sopenharmony_ci		sfp_sm_mod_next(sfp, SFP_MOD_WAITDEV, 0);
241062306a36Sopenharmony_ci		return;
241162306a36Sopenharmony_ci	}
241262306a36Sopenharmony_ci
241362306a36Sopenharmony_ci	switch (sfp->sm_mod_state) {
241462306a36Sopenharmony_ci	default:
241562306a36Sopenharmony_ci		if (event == SFP_E_INSERT) {
241662306a36Sopenharmony_ci			sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL);
241762306a36Sopenharmony_ci			sfp->sm_mod_tries_init = R_PROBE_RETRY_INIT;
241862306a36Sopenharmony_ci			sfp->sm_mod_tries = R_PROBE_RETRY_SLOW;
241962306a36Sopenharmony_ci		}
242062306a36Sopenharmony_ci		break;
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci	case SFP_MOD_PROBE:
242362306a36Sopenharmony_ci		/* Wait for T_PROBE_INIT to time out */
242462306a36Sopenharmony_ci		if (event != SFP_E_TIMEOUT)
242562306a36Sopenharmony_ci			break;
242662306a36Sopenharmony_ci
242762306a36Sopenharmony_ci		err = sfp_sm_mod_probe(sfp, sfp->sm_mod_tries == 1);
242862306a36Sopenharmony_ci		if (err == -EAGAIN) {
242962306a36Sopenharmony_ci			if (sfp->sm_mod_tries_init &&
243062306a36Sopenharmony_ci			   --sfp->sm_mod_tries_init) {
243162306a36Sopenharmony_ci				sfp_sm_set_timer(sfp, T_PROBE_RETRY_INIT);
243262306a36Sopenharmony_ci				break;
243362306a36Sopenharmony_ci			} else if (sfp->sm_mod_tries && --sfp->sm_mod_tries) {
243462306a36Sopenharmony_ci				if (sfp->sm_mod_tries == R_PROBE_RETRY_SLOW - 1)
243562306a36Sopenharmony_ci					dev_warn(sfp->dev,
243662306a36Sopenharmony_ci						 "please wait, module slow to respond\n");
243762306a36Sopenharmony_ci				sfp_sm_set_timer(sfp, T_PROBE_RETRY_SLOW);
243862306a36Sopenharmony_ci				break;
243962306a36Sopenharmony_ci			}
244062306a36Sopenharmony_ci		}
244162306a36Sopenharmony_ci		if (err < 0) {
244262306a36Sopenharmony_ci			sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
244362306a36Sopenharmony_ci			break;
244462306a36Sopenharmony_ci		}
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci		/* Force a poll to re-read the hardware signal state after
244762306a36Sopenharmony_ci		 * sfp_sm_mod_probe() changed state_hw_mask.
244862306a36Sopenharmony_ci		 */
244962306a36Sopenharmony_ci		mod_delayed_work(system_wq, &sfp->poll, 1);
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci		err = sfp_hwmon_insert(sfp);
245262306a36Sopenharmony_ci		if (err)
245362306a36Sopenharmony_ci			dev_warn(sfp->dev, "hwmon probe failed: %pe\n",
245462306a36Sopenharmony_ci				 ERR_PTR(err));
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_ci		sfp_sm_mod_next(sfp, SFP_MOD_WAITDEV, 0);
245762306a36Sopenharmony_ci		fallthrough;
245862306a36Sopenharmony_ci	case SFP_MOD_WAITDEV:
245962306a36Sopenharmony_ci		/* Ensure that the device is attached before proceeding */
246062306a36Sopenharmony_ci		if (sfp->sm_dev_state < SFP_DEV_DOWN)
246162306a36Sopenharmony_ci			break;
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci		/* Report the module insertion to the upstream device */
246462306a36Sopenharmony_ci		err = sfp_module_insert(sfp->sfp_bus, &sfp->id,
246562306a36Sopenharmony_ci					sfp->quirk);
246662306a36Sopenharmony_ci		if (err < 0) {
246762306a36Sopenharmony_ci			sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
246862306a36Sopenharmony_ci			break;
246962306a36Sopenharmony_ci		}
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci		/* If this is a power level 1 module, we are done */
247262306a36Sopenharmony_ci		if (sfp->module_power_mW <= 1000)
247362306a36Sopenharmony_ci			goto insert;
247462306a36Sopenharmony_ci
247562306a36Sopenharmony_ci		sfp_sm_mod_next(sfp, SFP_MOD_HPOWER, 0);
247662306a36Sopenharmony_ci		fallthrough;
247762306a36Sopenharmony_ci	case SFP_MOD_HPOWER:
247862306a36Sopenharmony_ci		/* Enable high power mode */
247962306a36Sopenharmony_ci		err = sfp_sm_mod_hpower(sfp, true);
248062306a36Sopenharmony_ci		if (err < 0) {
248162306a36Sopenharmony_ci			if (err != -EAGAIN) {
248262306a36Sopenharmony_ci				sfp_module_remove(sfp->sfp_bus);
248362306a36Sopenharmony_ci				sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
248462306a36Sopenharmony_ci			} else {
248562306a36Sopenharmony_ci				sfp_sm_set_timer(sfp, T_PROBE_RETRY_INIT);
248662306a36Sopenharmony_ci			}
248762306a36Sopenharmony_ci			break;
248862306a36Sopenharmony_ci		}
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_ci		sfp_sm_mod_next(sfp, SFP_MOD_WAITPWR, T_HPOWER_LEVEL);
249162306a36Sopenharmony_ci		break;
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_ci	case SFP_MOD_WAITPWR:
249462306a36Sopenharmony_ci		/* Wait for T_HPOWER_LEVEL to time out */
249562306a36Sopenharmony_ci		if (event != SFP_E_TIMEOUT)
249662306a36Sopenharmony_ci			break;
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	insert:
249962306a36Sopenharmony_ci		sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0);
250062306a36Sopenharmony_ci		break;
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci	case SFP_MOD_PRESENT:
250362306a36Sopenharmony_ci	case SFP_MOD_ERROR:
250462306a36Sopenharmony_ci		break;
250562306a36Sopenharmony_ci	}
250662306a36Sopenharmony_ci}
250762306a36Sopenharmony_ci
250862306a36Sopenharmony_cistatic void sfp_sm_main(struct sfp *sfp, unsigned int event)
250962306a36Sopenharmony_ci{
251062306a36Sopenharmony_ci	unsigned long timeout;
251162306a36Sopenharmony_ci	int ret;
251262306a36Sopenharmony_ci
251362306a36Sopenharmony_ci	/* Some events are global */
251462306a36Sopenharmony_ci	if (sfp->sm_state != SFP_S_DOWN &&
251562306a36Sopenharmony_ci	    (sfp->sm_mod_state != SFP_MOD_PRESENT ||
251662306a36Sopenharmony_ci	     sfp->sm_dev_state != SFP_DEV_UP)) {
251762306a36Sopenharmony_ci		if (sfp->sm_state == SFP_S_LINK_UP &&
251862306a36Sopenharmony_ci		    sfp->sm_dev_state == SFP_DEV_UP)
251962306a36Sopenharmony_ci			sfp_sm_link_down(sfp);
252062306a36Sopenharmony_ci		if (sfp->sm_state > SFP_S_INIT)
252162306a36Sopenharmony_ci			sfp_module_stop(sfp->sfp_bus);
252262306a36Sopenharmony_ci		if (sfp->mod_phy)
252362306a36Sopenharmony_ci			sfp_sm_phy_detach(sfp);
252462306a36Sopenharmony_ci		if (sfp->i2c_mii)
252562306a36Sopenharmony_ci			sfp_i2c_mdiobus_destroy(sfp);
252662306a36Sopenharmony_ci		sfp_module_tx_disable(sfp);
252762306a36Sopenharmony_ci		sfp_soft_stop_poll(sfp);
252862306a36Sopenharmony_ci		sfp_sm_next(sfp, SFP_S_DOWN, 0);
252962306a36Sopenharmony_ci		return;
253062306a36Sopenharmony_ci	}
253162306a36Sopenharmony_ci
253262306a36Sopenharmony_ci	/* The main state machine */
253362306a36Sopenharmony_ci	switch (sfp->sm_state) {
253462306a36Sopenharmony_ci	case SFP_S_DOWN:
253562306a36Sopenharmony_ci		if (sfp->sm_mod_state != SFP_MOD_PRESENT ||
253662306a36Sopenharmony_ci		    sfp->sm_dev_state != SFP_DEV_UP)
253762306a36Sopenharmony_ci			break;
253862306a36Sopenharmony_ci
253962306a36Sopenharmony_ci		/* Only use the soft state bits if we have access to the A2h
254062306a36Sopenharmony_ci		 * memory, which implies that we have some level of SFF-8472
254162306a36Sopenharmony_ci		 * compliance.
254262306a36Sopenharmony_ci		 */
254362306a36Sopenharmony_ci		if (sfp->have_a2)
254462306a36Sopenharmony_ci			sfp_soft_start_poll(sfp);
254562306a36Sopenharmony_ci
254662306a36Sopenharmony_ci		sfp_module_tx_enable(sfp);
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_ci		/* Initialise the fault clearance retries */
254962306a36Sopenharmony_ci		sfp->sm_fault_retries = N_FAULT_INIT;
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_ci		/* We need to check the TX_FAULT state, which is not defined
255262306a36Sopenharmony_ci		 * while TX_DISABLE is asserted. The earliest we want to do
255362306a36Sopenharmony_ci		 * anything (such as probe for a PHY) is 50ms (or more on
255462306a36Sopenharmony_ci		 * specific modules).
255562306a36Sopenharmony_ci		 */
255662306a36Sopenharmony_ci		sfp_sm_next(sfp, SFP_S_WAIT, sfp->module_t_wait);
255762306a36Sopenharmony_ci		break;
255862306a36Sopenharmony_ci
255962306a36Sopenharmony_ci	case SFP_S_WAIT:
256062306a36Sopenharmony_ci		if (event != SFP_E_TIMEOUT)
256162306a36Sopenharmony_ci			break;
256262306a36Sopenharmony_ci
256362306a36Sopenharmony_ci		if (sfp->state & SFP_F_TX_FAULT) {
256462306a36Sopenharmony_ci			/* Wait up to t_init (SFF-8472) or t_start_up (SFF-8431)
256562306a36Sopenharmony_ci			 * from the TX_DISABLE deassertion for the module to
256662306a36Sopenharmony_ci			 * initialise, which is indicated by TX_FAULT
256762306a36Sopenharmony_ci			 * deasserting.
256862306a36Sopenharmony_ci			 */
256962306a36Sopenharmony_ci			timeout = sfp->module_t_start_up;
257062306a36Sopenharmony_ci			if (timeout > sfp->module_t_wait)
257162306a36Sopenharmony_ci				timeout -= sfp->module_t_wait;
257262306a36Sopenharmony_ci			else
257362306a36Sopenharmony_ci				timeout = 1;
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_ci			sfp_sm_next(sfp, SFP_S_INIT, timeout);
257662306a36Sopenharmony_ci		} else {
257762306a36Sopenharmony_ci			/* TX_FAULT is not asserted, assume the module has
257862306a36Sopenharmony_ci			 * finished initialising.
257962306a36Sopenharmony_ci			 */
258062306a36Sopenharmony_ci			goto init_done;
258162306a36Sopenharmony_ci		}
258262306a36Sopenharmony_ci		break;
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci	case SFP_S_INIT:
258562306a36Sopenharmony_ci		if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT) {
258662306a36Sopenharmony_ci			/* TX_FAULT is still asserted after t_init
258762306a36Sopenharmony_ci			 * or t_start_up, so assume there is a fault.
258862306a36Sopenharmony_ci			 */
258962306a36Sopenharmony_ci			sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT,
259062306a36Sopenharmony_ci				     sfp->sm_fault_retries == N_FAULT_INIT);
259162306a36Sopenharmony_ci		} else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) {
259262306a36Sopenharmony_ci	init_done:
259362306a36Sopenharmony_ci			/* Create mdiobus and start trying for PHY */
259462306a36Sopenharmony_ci			ret = sfp_sm_add_mdio_bus(sfp);
259562306a36Sopenharmony_ci			if (ret < 0) {
259662306a36Sopenharmony_ci				sfp_sm_next(sfp, SFP_S_FAIL, 0);
259762306a36Sopenharmony_ci				break;
259862306a36Sopenharmony_ci			}
259962306a36Sopenharmony_ci			sfp->sm_phy_retries = R_PHY_RETRY;
260062306a36Sopenharmony_ci			goto phy_probe;
260162306a36Sopenharmony_ci		}
260262306a36Sopenharmony_ci		break;
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_ci	case SFP_S_INIT_PHY:
260562306a36Sopenharmony_ci		if (event != SFP_E_TIMEOUT)
260662306a36Sopenharmony_ci			break;
260762306a36Sopenharmony_ci	phy_probe:
260862306a36Sopenharmony_ci		/* TX_FAULT deasserted or we timed out with TX_FAULT
260962306a36Sopenharmony_ci		 * clear.  Probe for the PHY and check the LOS state.
261062306a36Sopenharmony_ci		 */
261162306a36Sopenharmony_ci		ret = sfp_sm_probe_for_phy(sfp);
261262306a36Sopenharmony_ci		if (ret == -ENODEV) {
261362306a36Sopenharmony_ci			if (--sfp->sm_phy_retries) {
261462306a36Sopenharmony_ci				sfp_sm_next(sfp, SFP_S_INIT_PHY, T_PHY_RETRY);
261562306a36Sopenharmony_ci				break;
261662306a36Sopenharmony_ci			} else {
261762306a36Sopenharmony_ci				dev_info(sfp->dev, "no PHY detected\n");
261862306a36Sopenharmony_ci			}
261962306a36Sopenharmony_ci		} else if (ret) {
262062306a36Sopenharmony_ci			sfp_sm_next(sfp, SFP_S_FAIL, 0);
262162306a36Sopenharmony_ci			break;
262262306a36Sopenharmony_ci		}
262362306a36Sopenharmony_ci		if (sfp_module_start(sfp->sfp_bus)) {
262462306a36Sopenharmony_ci			sfp_sm_next(sfp, SFP_S_FAIL, 0);
262562306a36Sopenharmony_ci			break;
262662306a36Sopenharmony_ci		}
262762306a36Sopenharmony_ci		sfp_sm_link_check_los(sfp);
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci		/* Reset the fault retry count */
263062306a36Sopenharmony_ci		sfp->sm_fault_retries = N_FAULT;
263162306a36Sopenharmony_ci		break;
263262306a36Sopenharmony_ci
263362306a36Sopenharmony_ci	case SFP_S_INIT_TX_FAULT:
263462306a36Sopenharmony_ci		if (event == SFP_E_TIMEOUT) {
263562306a36Sopenharmony_ci			sfp_module_tx_fault_reset(sfp);
263662306a36Sopenharmony_ci			sfp_sm_next(sfp, SFP_S_INIT, sfp->module_t_start_up);
263762306a36Sopenharmony_ci		}
263862306a36Sopenharmony_ci		break;
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_ci	case SFP_S_WAIT_LOS:
264162306a36Sopenharmony_ci		if (event == SFP_E_TX_FAULT)
264262306a36Sopenharmony_ci			sfp_sm_fault(sfp, SFP_S_TX_FAULT, true);
264362306a36Sopenharmony_ci		else if (sfp_los_event_inactive(sfp, event))
264462306a36Sopenharmony_ci			sfp_sm_link_up(sfp);
264562306a36Sopenharmony_ci		break;
264662306a36Sopenharmony_ci
264762306a36Sopenharmony_ci	case SFP_S_LINK_UP:
264862306a36Sopenharmony_ci		if (event == SFP_E_TX_FAULT) {
264962306a36Sopenharmony_ci			sfp_sm_link_down(sfp);
265062306a36Sopenharmony_ci			sfp_sm_fault(sfp, SFP_S_TX_FAULT, true);
265162306a36Sopenharmony_ci		} else if (sfp_los_event_active(sfp, event)) {
265262306a36Sopenharmony_ci			sfp_sm_link_down(sfp);
265362306a36Sopenharmony_ci			sfp_sm_next(sfp, SFP_S_WAIT_LOS, 0);
265462306a36Sopenharmony_ci		}
265562306a36Sopenharmony_ci		break;
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_ci	case SFP_S_TX_FAULT:
265862306a36Sopenharmony_ci		if (event == SFP_E_TIMEOUT) {
265962306a36Sopenharmony_ci			sfp_module_tx_fault_reset(sfp);
266062306a36Sopenharmony_ci			sfp_sm_next(sfp, SFP_S_REINIT, sfp->module_t_start_up);
266162306a36Sopenharmony_ci		}
266262306a36Sopenharmony_ci		break;
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci	case SFP_S_REINIT:
266562306a36Sopenharmony_ci		if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT) {
266662306a36Sopenharmony_ci			sfp_sm_fault(sfp, SFP_S_TX_FAULT, false);
266762306a36Sopenharmony_ci		} else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) {
266862306a36Sopenharmony_ci			dev_info(sfp->dev, "module transmit fault recovered\n");
266962306a36Sopenharmony_ci			sfp_sm_link_check_los(sfp);
267062306a36Sopenharmony_ci		}
267162306a36Sopenharmony_ci		break;
267262306a36Sopenharmony_ci
267362306a36Sopenharmony_ci	case SFP_S_TX_DISABLE:
267462306a36Sopenharmony_ci		break;
267562306a36Sopenharmony_ci	}
267662306a36Sopenharmony_ci}
267762306a36Sopenharmony_ci
267862306a36Sopenharmony_cistatic void __sfp_sm_event(struct sfp *sfp, unsigned int event)
267962306a36Sopenharmony_ci{
268062306a36Sopenharmony_ci	dev_dbg(sfp->dev, "SM: enter %s:%s:%s event %s\n",
268162306a36Sopenharmony_ci		mod_state_to_str(sfp->sm_mod_state),
268262306a36Sopenharmony_ci		dev_state_to_str(sfp->sm_dev_state),
268362306a36Sopenharmony_ci		sm_state_to_str(sfp->sm_state),
268462306a36Sopenharmony_ci		event_to_str(event));
268562306a36Sopenharmony_ci
268662306a36Sopenharmony_ci	sfp_sm_device(sfp, event);
268762306a36Sopenharmony_ci	sfp_sm_module(sfp, event);
268862306a36Sopenharmony_ci	sfp_sm_main(sfp, event);
268962306a36Sopenharmony_ci
269062306a36Sopenharmony_ci	dev_dbg(sfp->dev, "SM: exit %s:%s:%s\n",
269162306a36Sopenharmony_ci		mod_state_to_str(sfp->sm_mod_state),
269262306a36Sopenharmony_ci		dev_state_to_str(sfp->sm_dev_state),
269362306a36Sopenharmony_ci		sm_state_to_str(sfp->sm_state));
269462306a36Sopenharmony_ci}
269562306a36Sopenharmony_ci
269662306a36Sopenharmony_cistatic void sfp_sm_event(struct sfp *sfp, unsigned int event)
269762306a36Sopenharmony_ci{
269862306a36Sopenharmony_ci	mutex_lock(&sfp->sm_mutex);
269962306a36Sopenharmony_ci	__sfp_sm_event(sfp, event);
270062306a36Sopenharmony_ci	mutex_unlock(&sfp->sm_mutex);
270162306a36Sopenharmony_ci}
270262306a36Sopenharmony_ci
270362306a36Sopenharmony_cistatic void sfp_attach(struct sfp *sfp)
270462306a36Sopenharmony_ci{
270562306a36Sopenharmony_ci	sfp_sm_event(sfp, SFP_E_DEV_ATTACH);
270662306a36Sopenharmony_ci}
270762306a36Sopenharmony_ci
270862306a36Sopenharmony_cistatic void sfp_detach(struct sfp *sfp)
270962306a36Sopenharmony_ci{
271062306a36Sopenharmony_ci	sfp_sm_event(sfp, SFP_E_DEV_DETACH);
271162306a36Sopenharmony_ci}
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_cistatic void sfp_start(struct sfp *sfp)
271462306a36Sopenharmony_ci{
271562306a36Sopenharmony_ci	sfp_sm_event(sfp, SFP_E_DEV_UP);
271662306a36Sopenharmony_ci}
271762306a36Sopenharmony_ci
271862306a36Sopenharmony_cistatic void sfp_stop(struct sfp *sfp)
271962306a36Sopenharmony_ci{
272062306a36Sopenharmony_ci	sfp_sm_event(sfp, SFP_E_DEV_DOWN);
272162306a36Sopenharmony_ci}
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_cistatic void sfp_set_signal_rate(struct sfp *sfp, unsigned int rate_kbd)
272462306a36Sopenharmony_ci{
272562306a36Sopenharmony_ci	unsigned int set;
272662306a36Sopenharmony_ci
272762306a36Sopenharmony_ci	sfp->rate_kbd = rate_kbd;
272862306a36Sopenharmony_ci
272962306a36Sopenharmony_ci	if (rate_kbd > sfp->rs_threshold_kbd)
273062306a36Sopenharmony_ci		set = sfp->rs_state_mask;
273162306a36Sopenharmony_ci	else
273262306a36Sopenharmony_ci		set = 0;
273362306a36Sopenharmony_ci
273462306a36Sopenharmony_ci	sfp_mod_state(sfp, SFP_F_RS0 | SFP_F_RS1, set);
273562306a36Sopenharmony_ci}
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_cistatic int sfp_module_info(struct sfp *sfp, struct ethtool_modinfo *modinfo)
273862306a36Sopenharmony_ci{
273962306a36Sopenharmony_ci	/* locking... and check module is present */
274062306a36Sopenharmony_ci
274162306a36Sopenharmony_ci	if (sfp->id.ext.sff8472_compliance &&
274262306a36Sopenharmony_ci	    !(sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE)) {
274362306a36Sopenharmony_ci		modinfo->type = ETH_MODULE_SFF_8472;
274462306a36Sopenharmony_ci		modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
274562306a36Sopenharmony_ci	} else {
274662306a36Sopenharmony_ci		modinfo->type = ETH_MODULE_SFF_8079;
274762306a36Sopenharmony_ci		modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
274862306a36Sopenharmony_ci	}
274962306a36Sopenharmony_ci	return 0;
275062306a36Sopenharmony_ci}
275162306a36Sopenharmony_ci
275262306a36Sopenharmony_cistatic int sfp_module_eeprom(struct sfp *sfp, struct ethtool_eeprom *ee,
275362306a36Sopenharmony_ci			     u8 *data)
275462306a36Sopenharmony_ci{
275562306a36Sopenharmony_ci	unsigned int first, last, len;
275662306a36Sopenharmony_ci	int ret;
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_ci	if (!(sfp->state & SFP_F_PRESENT))
275962306a36Sopenharmony_ci		return -ENODEV;
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci	if (ee->len == 0)
276262306a36Sopenharmony_ci		return -EINVAL;
276362306a36Sopenharmony_ci
276462306a36Sopenharmony_ci	first = ee->offset;
276562306a36Sopenharmony_ci	last = ee->offset + ee->len;
276662306a36Sopenharmony_ci	if (first < ETH_MODULE_SFF_8079_LEN) {
276762306a36Sopenharmony_ci		len = min_t(unsigned int, last, ETH_MODULE_SFF_8079_LEN);
276862306a36Sopenharmony_ci		len -= first;
276962306a36Sopenharmony_ci
277062306a36Sopenharmony_ci		ret = sfp_read(sfp, false, first, data, len);
277162306a36Sopenharmony_ci		if (ret < 0)
277262306a36Sopenharmony_ci			return ret;
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_ci		first += len;
277562306a36Sopenharmony_ci		data += len;
277662306a36Sopenharmony_ci	}
277762306a36Sopenharmony_ci	if (first < ETH_MODULE_SFF_8472_LEN && last > ETH_MODULE_SFF_8079_LEN) {
277862306a36Sopenharmony_ci		len = min_t(unsigned int, last, ETH_MODULE_SFF_8472_LEN);
277962306a36Sopenharmony_ci		len -= first;
278062306a36Sopenharmony_ci		first -= ETH_MODULE_SFF_8079_LEN;
278162306a36Sopenharmony_ci
278262306a36Sopenharmony_ci		ret = sfp_read(sfp, true, first, data, len);
278362306a36Sopenharmony_ci		if (ret < 0)
278462306a36Sopenharmony_ci			return ret;
278562306a36Sopenharmony_ci	}
278662306a36Sopenharmony_ci	return 0;
278762306a36Sopenharmony_ci}
278862306a36Sopenharmony_ci
278962306a36Sopenharmony_cistatic int sfp_module_eeprom_by_page(struct sfp *sfp,
279062306a36Sopenharmony_ci				     const struct ethtool_module_eeprom *page,
279162306a36Sopenharmony_ci				     struct netlink_ext_ack *extack)
279262306a36Sopenharmony_ci{
279362306a36Sopenharmony_ci	if (!(sfp->state & SFP_F_PRESENT))
279462306a36Sopenharmony_ci		return -ENODEV;
279562306a36Sopenharmony_ci
279662306a36Sopenharmony_ci	if (page->bank) {
279762306a36Sopenharmony_ci		NL_SET_ERR_MSG(extack, "Banks not supported");
279862306a36Sopenharmony_ci		return -EOPNOTSUPP;
279962306a36Sopenharmony_ci	}
280062306a36Sopenharmony_ci
280162306a36Sopenharmony_ci	if (page->page) {
280262306a36Sopenharmony_ci		NL_SET_ERR_MSG(extack, "Only page 0 supported");
280362306a36Sopenharmony_ci		return -EOPNOTSUPP;
280462306a36Sopenharmony_ci	}
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci	if (page->i2c_address != 0x50 &&
280762306a36Sopenharmony_ci	    page->i2c_address != 0x51) {
280862306a36Sopenharmony_ci		NL_SET_ERR_MSG(extack, "Only address 0x50 and 0x51 supported");
280962306a36Sopenharmony_ci		return -EOPNOTSUPP;
281062306a36Sopenharmony_ci	}
281162306a36Sopenharmony_ci
281262306a36Sopenharmony_ci	return sfp_read(sfp, page->i2c_address == 0x51, page->offset,
281362306a36Sopenharmony_ci			page->data, page->length);
281462306a36Sopenharmony_ci};
281562306a36Sopenharmony_ci
281662306a36Sopenharmony_cistatic const struct sfp_socket_ops sfp_module_ops = {
281762306a36Sopenharmony_ci	.attach = sfp_attach,
281862306a36Sopenharmony_ci	.detach = sfp_detach,
281962306a36Sopenharmony_ci	.start = sfp_start,
282062306a36Sopenharmony_ci	.stop = sfp_stop,
282162306a36Sopenharmony_ci	.set_signal_rate = sfp_set_signal_rate,
282262306a36Sopenharmony_ci	.module_info = sfp_module_info,
282362306a36Sopenharmony_ci	.module_eeprom = sfp_module_eeprom,
282462306a36Sopenharmony_ci	.module_eeprom_by_page = sfp_module_eeprom_by_page,
282562306a36Sopenharmony_ci};
282662306a36Sopenharmony_ci
282762306a36Sopenharmony_cistatic void sfp_timeout(struct work_struct *work)
282862306a36Sopenharmony_ci{
282962306a36Sopenharmony_ci	struct sfp *sfp = container_of(work, struct sfp, timeout.work);
283062306a36Sopenharmony_ci
283162306a36Sopenharmony_ci	rtnl_lock();
283262306a36Sopenharmony_ci	sfp_sm_event(sfp, SFP_E_TIMEOUT);
283362306a36Sopenharmony_ci	rtnl_unlock();
283462306a36Sopenharmony_ci}
283562306a36Sopenharmony_ci
283662306a36Sopenharmony_cistatic void sfp_check_state(struct sfp *sfp)
283762306a36Sopenharmony_ci{
283862306a36Sopenharmony_ci	unsigned int state, i, changed;
283962306a36Sopenharmony_ci
284062306a36Sopenharmony_ci	rtnl_lock();
284162306a36Sopenharmony_ci	mutex_lock(&sfp->st_mutex);
284262306a36Sopenharmony_ci	state = sfp_get_state(sfp);
284362306a36Sopenharmony_ci	changed = state ^ sfp->state;
284462306a36Sopenharmony_ci	if (sfp->tx_fault_ignore)
284562306a36Sopenharmony_ci		changed &= SFP_F_PRESENT | SFP_F_LOS;
284662306a36Sopenharmony_ci	else
284762306a36Sopenharmony_ci		changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT;
284862306a36Sopenharmony_ci
284962306a36Sopenharmony_ci	for (i = 0; i < GPIO_MAX; i++)
285062306a36Sopenharmony_ci		if (changed & BIT(i))
285162306a36Sopenharmony_ci			dev_dbg(sfp->dev, "%s %u -> %u\n", gpio_names[i],
285262306a36Sopenharmony_ci				!!(sfp->state & BIT(i)), !!(state & BIT(i)));
285362306a36Sopenharmony_ci
285462306a36Sopenharmony_ci	state |= sfp->state & SFP_F_OUTPUTS;
285562306a36Sopenharmony_ci	sfp->state = state;
285662306a36Sopenharmony_ci	mutex_unlock(&sfp->st_mutex);
285762306a36Sopenharmony_ci
285862306a36Sopenharmony_ci	mutex_lock(&sfp->sm_mutex);
285962306a36Sopenharmony_ci	if (changed & SFP_F_PRESENT)
286062306a36Sopenharmony_ci		__sfp_sm_event(sfp, state & SFP_F_PRESENT ?
286162306a36Sopenharmony_ci				    SFP_E_INSERT : SFP_E_REMOVE);
286262306a36Sopenharmony_ci
286362306a36Sopenharmony_ci	if (changed & SFP_F_TX_FAULT)
286462306a36Sopenharmony_ci		__sfp_sm_event(sfp, state & SFP_F_TX_FAULT ?
286562306a36Sopenharmony_ci				    SFP_E_TX_FAULT : SFP_E_TX_CLEAR);
286662306a36Sopenharmony_ci
286762306a36Sopenharmony_ci	if (changed & SFP_F_LOS)
286862306a36Sopenharmony_ci		__sfp_sm_event(sfp, state & SFP_F_LOS ?
286962306a36Sopenharmony_ci				    SFP_E_LOS_HIGH : SFP_E_LOS_LOW);
287062306a36Sopenharmony_ci	mutex_unlock(&sfp->sm_mutex);
287162306a36Sopenharmony_ci	rtnl_unlock();
287262306a36Sopenharmony_ci}
287362306a36Sopenharmony_ci
287462306a36Sopenharmony_cistatic irqreturn_t sfp_irq(int irq, void *data)
287562306a36Sopenharmony_ci{
287662306a36Sopenharmony_ci	struct sfp *sfp = data;
287762306a36Sopenharmony_ci
287862306a36Sopenharmony_ci	sfp_check_state(sfp);
287962306a36Sopenharmony_ci
288062306a36Sopenharmony_ci	return IRQ_HANDLED;
288162306a36Sopenharmony_ci}
288262306a36Sopenharmony_ci
288362306a36Sopenharmony_cistatic void sfp_poll(struct work_struct *work)
288462306a36Sopenharmony_ci{
288562306a36Sopenharmony_ci	struct sfp *sfp = container_of(work, struct sfp, poll.work);
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci	sfp_check_state(sfp);
288862306a36Sopenharmony_ci
288962306a36Sopenharmony_ci	// st_mutex doesn't need to be held here for state_soft_mask,
289062306a36Sopenharmony_ci	// it's unimportant if we race while reading this.
289162306a36Sopenharmony_ci	if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) ||
289262306a36Sopenharmony_ci	    sfp->need_poll)
289362306a36Sopenharmony_ci		mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
289462306a36Sopenharmony_ci}
289562306a36Sopenharmony_ci
289662306a36Sopenharmony_cistatic struct sfp *sfp_alloc(struct device *dev)
289762306a36Sopenharmony_ci{
289862306a36Sopenharmony_ci	struct sfp *sfp;
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_ci	sfp = kzalloc(sizeof(*sfp), GFP_KERNEL);
290162306a36Sopenharmony_ci	if (!sfp)
290262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
290362306a36Sopenharmony_ci
290462306a36Sopenharmony_ci	sfp->dev = dev;
290562306a36Sopenharmony_ci	sfp->i2c_block_size = SFP_EEPROM_BLOCK_SIZE;
290662306a36Sopenharmony_ci
290762306a36Sopenharmony_ci	mutex_init(&sfp->sm_mutex);
290862306a36Sopenharmony_ci	mutex_init(&sfp->st_mutex);
290962306a36Sopenharmony_ci	INIT_DELAYED_WORK(&sfp->poll, sfp_poll);
291062306a36Sopenharmony_ci	INIT_DELAYED_WORK(&sfp->timeout, sfp_timeout);
291162306a36Sopenharmony_ci
291262306a36Sopenharmony_ci	sfp_hwmon_init(sfp);
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_ci	return sfp;
291562306a36Sopenharmony_ci}
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_cistatic void sfp_cleanup(void *data)
291862306a36Sopenharmony_ci{
291962306a36Sopenharmony_ci	struct sfp *sfp = data;
292062306a36Sopenharmony_ci
292162306a36Sopenharmony_ci	sfp_hwmon_exit(sfp);
292262306a36Sopenharmony_ci
292362306a36Sopenharmony_ci	cancel_delayed_work_sync(&sfp->poll);
292462306a36Sopenharmony_ci	cancel_delayed_work_sync(&sfp->timeout);
292562306a36Sopenharmony_ci	if (sfp->i2c_mii) {
292662306a36Sopenharmony_ci		mdiobus_unregister(sfp->i2c_mii);
292762306a36Sopenharmony_ci		mdiobus_free(sfp->i2c_mii);
292862306a36Sopenharmony_ci	}
292962306a36Sopenharmony_ci	if (sfp->i2c)
293062306a36Sopenharmony_ci		i2c_put_adapter(sfp->i2c);
293162306a36Sopenharmony_ci	kfree(sfp);
293262306a36Sopenharmony_ci}
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_cistatic int sfp_i2c_get(struct sfp *sfp)
293562306a36Sopenharmony_ci{
293662306a36Sopenharmony_ci	struct fwnode_handle *h;
293762306a36Sopenharmony_ci	struct i2c_adapter *i2c;
293862306a36Sopenharmony_ci	int err;
293962306a36Sopenharmony_ci
294062306a36Sopenharmony_ci	h = fwnode_find_reference(dev_fwnode(sfp->dev), "i2c-bus", 0);
294162306a36Sopenharmony_ci	if (IS_ERR(h)) {
294262306a36Sopenharmony_ci		dev_err(sfp->dev, "missing 'i2c-bus' property\n");
294362306a36Sopenharmony_ci		return -ENODEV;
294462306a36Sopenharmony_ci	}
294562306a36Sopenharmony_ci
294662306a36Sopenharmony_ci	i2c = i2c_get_adapter_by_fwnode(h);
294762306a36Sopenharmony_ci	if (!i2c) {
294862306a36Sopenharmony_ci		err = -EPROBE_DEFER;
294962306a36Sopenharmony_ci		goto put;
295062306a36Sopenharmony_ci	}
295162306a36Sopenharmony_ci
295262306a36Sopenharmony_ci	err = sfp_i2c_configure(sfp, i2c);
295362306a36Sopenharmony_ci	if (err)
295462306a36Sopenharmony_ci		i2c_put_adapter(i2c);
295562306a36Sopenharmony_ciput:
295662306a36Sopenharmony_ci	fwnode_handle_put(h);
295762306a36Sopenharmony_ci	return err;
295862306a36Sopenharmony_ci}
295962306a36Sopenharmony_ci
296062306a36Sopenharmony_cistatic int sfp_probe(struct platform_device *pdev)
296162306a36Sopenharmony_ci{
296262306a36Sopenharmony_ci	const struct sff_data *sff;
296362306a36Sopenharmony_ci	char *sfp_irq_name;
296462306a36Sopenharmony_ci	struct sfp *sfp;
296562306a36Sopenharmony_ci	int err, i;
296662306a36Sopenharmony_ci
296762306a36Sopenharmony_ci	sfp = sfp_alloc(&pdev->dev);
296862306a36Sopenharmony_ci	if (IS_ERR(sfp))
296962306a36Sopenharmony_ci		return PTR_ERR(sfp);
297062306a36Sopenharmony_ci
297162306a36Sopenharmony_ci	platform_set_drvdata(pdev, sfp);
297262306a36Sopenharmony_ci
297362306a36Sopenharmony_ci	err = devm_add_action_or_reset(sfp->dev, sfp_cleanup, sfp);
297462306a36Sopenharmony_ci	if (err < 0)
297562306a36Sopenharmony_ci		return err;
297662306a36Sopenharmony_ci
297762306a36Sopenharmony_ci	sff = device_get_match_data(sfp->dev);
297862306a36Sopenharmony_ci	if (!sff)
297962306a36Sopenharmony_ci		sff = &sfp_data;
298062306a36Sopenharmony_ci
298162306a36Sopenharmony_ci	sfp->type = sff;
298262306a36Sopenharmony_ci
298362306a36Sopenharmony_ci	err = sfp_i2c_get(sfp);
298462306a36Sopenharmony_ci	if (err)
298562306a36Sopenharmony_ci		return err;
298662306a36Sopenharmony_ci
298762306a36Sopenharmony_ci	for (i = 0; i < GPIO_MAX; i++)
298862306a36Sopenharmony_ci		if (sff->gpios & BIT(i)) {
298962306a36Sopenharmony_ci			sfp->gpio[i] = devm_gpiod_get_optional(sfp->dev,
299062306a36Sopenharmony_ci					   gpio_names[i], gpio_flags[i]);
299162306a36Sopenharmony_ci			if (IS_ERR(sfp->gpio[i]))
299262306a36Sopenharmony_ci				return PTR_ERR(sfp->gpio[i]);
299362306a36Sopenharmony_ci		}
299462306a36Sopenharmony_ci
299562306a36Sopenharmony_ci	sfp->state_hw_mask = SFP_F_PRESENT;
299662306a36Sopenharmony_ci	sfp->state_hw_drive = SFP_F_TX_DISABLE;
299762306a36Sopenharmony_ci
299862306a36Sopenharmony_ci	sfp->get_state = sfp_gpio_get_state;
299962306a36Sopenharmony_ci	sfp->set_state = sfp_gpio_set_state;
300062306a36Sopenharmony_ci
300162306a36Sopenharmony_ci	/* Modules that have no detect signal are always present */
300262306a36Sopenharmony_ci	if (!(sfp->gpio[GPIO_MODDEF0]))
300362306a36Sopenharmony_ci		sfp->get_state = sff_gpio_get_state;
300462306a36Sopenharmony_ci
300562306a36Sopenharmony_ci	device_property_read_u32(&pdev->dev, "maximum-power-milliwatt",
300662306a36Sopenharmony_ci				 &sfp->max_power_mW);
300762306a36Sopenharmony_ci	if (sfp->max_power_mW < 1000) {
300862306a36Sopenharmony_ci		if (sfp->max_power_mW)
300962306a36Sopenharmony_ci			dev_warn(sfp->dev,
301062306a36Sopenharmony_ci				 "Firmware bug: host maximum power should be at least 1W\n");
301162306a36Sopenharmony_ci		sfp->max_power_mW = 1000;
301262306a36Sopenharmony_ci	}
301362306a36Sopenharmony_ci
301462306a36Sopenharmony_ci	dev_info(sfp->dev, "Host maximum power %u.%uW\n",
301562306a36Sopenharmony_ci		 sfp->max_power_mW / 1000, (sfp->max_power_mW / 100) % 10);
301662306a36Sopenharmony_ci
301762306a36Sopenharmony_ci	/* Get the initial state, and always signal TX disable,
301862306a36Sopenharmony_ci	 * since the network interface will not be up.
301962306a36Sopenharmony_ci	 */
302062306a36Sopenharmony_ci	sfp->state = sfp_get_state(sfp) | SFP_F_TX_DISABLE;
302162306a36Sopenharmony_ci
302262306a36Sopenharmony_ci	if (sfp->gpio[GPIO_RS0] &&
302362306a36Sopenharmony_ci	    gpiod_get_value_cansleep(sfp->gpio[GPIO_RS0]))
302462306a36Sopenharmony_ci		sfp->state |= SFP_F_RS0;
302562306a36Sopenharmony_ci	sfp_set_state(sfp, sfp->state);
302662306a36Sopenharmony_ci	sfp_module_tx_disable(sfp);
302762306a36Sopenharmony_ci	if (sfp->state & SFP_F_PRESENT) {
302862306a36Sopenharmony_ci		rtnl_lock();
302962306a36Sopenharmony_ci		sfp_sm_event(sfp, SFP_E_INSERT);
303062306a36Sopenharmony_ci		rtnl_unlock();
303162306a36Sopenharmony_ci	}
303262306a36Sopenharmony_ci
303362306a36Sopenharmony_ci	for (i = 0; i < GPIO_MAX; i++) {
303462306a36Sopenharmony_ci		if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i])
303562306a36Sopenharmony_ci			continue;
303662306a36Sopenharmony_ci
303762306a36Sopenharmony_ci		sfp->gpio_irq[i] = gpiod_to_irq(sfp->gpio[i]);
303862306a36Sopenharmony_ci		if (sfp->gpio_irq[i] < 0) {
303962306a36Sopenharmony_ci			sfp->gpio_irq[i] = 0;
304062306a36Sopenharmony_ci			sfp->need_poll = true;
304162306a36Sopenharmony_ci			continue;
304262306a36Sopenharmony_ci		}
304362306a36Sopenharmony_ci
304462306a36Sopenharmony_ci		sfp_irq_name = devm_kasprintf(sfp->dev, GFP_KERNEL,
304562306a36Sopenharmony_ci					      "%s-%s", dev_name(sfp->dev),
304662306a36Sopenharmony_ci					      gpio_names[i]);
304762306a36Sopenharmony_ci
304862306a36Sopenharmony_ci		if (!sfp_irq_name)
304962306a36Sopenharmony_ci			return -ENOMEM;
305062306a36Sopenharmony_ci
305162306a36Sopenharmony_ci		err = devm_request_threaded_irq(sfp->dev, sfp->gpio_irq[i],
305262306a36Sopenharmony_ci						NULL, sfp_irq,
305362306a36Sopenharmony_ci						IRQF_ONESHOT |
305462306a36Sopenharmony_ci						IRQF_TRIGGER_RISING |
305562306a36Sopenharmony_ci						IRQF_TRIGGER_FALLING,
305662306a36Sopenharmony_ci						sfp_irq_name, sfp);
305762306a36Sopenharmony_ci		if (err) {
305862306a36Sopenharmony_ci			sfp->gpio_irq[i] = 0;
305962306a36Sopenharmony_ci			sfp->need_poll = true;
306062306a36Sopenharmony_ci		}
306162306a36Sopenharmony_ci	}
306262306a36Sopenharmony_ci
306362306a36Sopenharmony_ci	if (sfp->need_poll)
306462306a36Sopenharmony_ci		mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_ci	/* We could have an issue in cases no Tx disable pin is available or
306762306a36Sopenharmony_ci	 * wired as modules using a laser as their light source will continue to
306862306a36Sopenharmony_ci	 * be active when the fiber is removed. This could be a safety issue and
306962306a36Sopenharmony_ci	 * we should at least warn the user about that.
307062306a36Sopenharmony_ci	 */
307162306a36Sopenharmony_ci	if (!sfp->gpio[GPIO_TX_DISABLE])
307262306a36Sopenharmony_ci		dev_warn(sfp->dev,
307362306a36Sopenharmony_ci			 "No tx_disable pin: SFP modules will always be emitting.\n");
307462306a36Sopenharmony_ci
307562306a36Sopenharmony_ci	sfp->sfp_bus = sfp_register_socket(sfp->dev, sfp, &sfp_module_ops);
307662306a36Sopenharmony_ci	if (!sfp->sfp_bus)
307762306a36Sopenharmony_ci		return -ENOMEM;
307862306a36Sopenharmony_ci
307962306a36Sopenharmony_ci	sfp_debugfs_init(sfp);
308062306a36Sopenharmony_ci
308162306a36Sopenharmony_ci	return 0;
308262306a36Sopenharmony_ci}
308362306a36Sopenharmony_ci
308462306a36Sopenharmony_cistatic int sfp_remove(struct platform_device *pdev)
308562306a36Sopenharmony_ci{
308662306a36Sopenharmony_ci	struct sfp *sfp = platform_get_drvdata(pdev);
308762306a36Sopenharmony_ci
308862306a36Sopenharmony_ci	sfp_debugfs_exit(sfp);
308962306a36Sopenharmony_ci	sfp_unregister_socket(sfp->sfp_bus);
309062306a36Sopenharmony_ci
309162306a36Sopenharmony_ci	rtnl_lock();
309262306a36Sopenharmony_ci	sfp_sm_event(sfp, SFP_E_REMOVE);
309362306a36Sopenharmony_ci	rtnl_unlock();
309462306a36Sopenharmony_ci
309562306a36Sopenharmony_ci	return 0;
309662306a36Sopenharmony_ci}
309762306a36Sopenharmony_ci
309862306a36Sopenharmony_cistatic void sfp_shutdown(struct platform_device *pdev)
309962306a36Sopenharmony_ci{
310062306a36Sopenharmony_ci	struct sfp *sfp = platform_get_drvdata(pdev);
310162306a36Sopenharmony_ci	int i;
310262306a36Sopenharmony_ci
310362306a36Sopenharmony_ci	for (i = 0; i < GPIO_MAX; i++) {
310462306a36Sopenharmony_ci		if (!sfp->gpio_irq[i])
310562306a36Sopenharmony_ci			continue;
310662306a36Sopenharmony_ci
310762306a36Sopenharmony_ci		devm_free_irq(sfp->dev, sfp->gpio_irq[i], sfp);
310862306a36Sopenharmony_ci	}
310962306a36Sopenharmony_ci
311062306a36Sopenharmony_ci	cancel_delayed_work_sync(&sfp->poll);
311162306a36Sopenharmony_ci	cancel_delayed_work_sync(&sfp->timeout);
311262306a36Sopenharmony_ci}
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_cistatic struct platform_driver sfp_driver = {
311562306a36Sopenharmony_ci	.probe = sfp_probe,
311662306a36Sopenharmony_ci	.remove = sfp_remove,
311762306a36Sopenharmony_ci	.shutdown = sfp_shutdown,
311862306a36Sopenharmony_ci	.driver = {
311962306a36Sopenharmony_ci		.name = "sfp",
312062306a36Sopenharmony_ci		.of_match_table = sfp_of_match,
312162306a36Sopenharmony_ci	},
312262306a36Sopenharmony_ci};
312362306a36Sopenharmony_ci
312462306a36Sopenharmony_cistatic int sfp_init(void)
312562306a36Sopenharmony_ci{
312662306a36Sopenharmony_ci	poll_jiffies = msecs_to_jiffies(100);
312762306a36Sopenharmony_ci
312862306a36Sopenharmony_ci	return platform_driver_register(&sfp_driver);
312962306a36Sopenharmony_ci}
313062306a36Sopenharmony_cimodule_init(sfp_init);
313162306a36Sopenharmony_ci
313262306a36Sopenharmony_cistatic void sfp_exit(void)
313362306a36Sopenharmony_ci{
313462306a36Sopenharmony_ci	platform_driver_unregister(&sfp_driver);
313562306a36Sopenharmony_ci}
313662306a36Sopenharmony_cimodule_exit(sfp_exit);
313762306a36Sopenharmony_ci
313862306a36Sopenharmony_ciMODULE_ALIAS("platform:sfp");
313962306a36Sopenharmony_ciMODULE_AUTHOR("Russell King");
314062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
3141