18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/acpi.h> 38c2ecf20Sopenharmony_ci#include <linux/ctype.h> 48c2ecf20Sopenharmony_ci#include <linux/delay.h> 58c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 68c2ecf20Sopenharmony_ci#include <linux/hwmon.h> 78c2ecf20Sopenharmony_ci#include <linux/i2c.h> 88c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 98c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 108c2ecf20Sopenharmony_ci#include <linux/mdio/mdio-i2c.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/mutex.h> 138c2ecf20Sopenharmony_ci#include <linux/of.h> 148c2ecf20Sopenharmony_ci#include <linux/phy.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "sfp.h" 218c2ecf20Sopenharmony_ci#include "swphy.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cienum { 248c2ecf20Sopenharmony_ci GPIO_MODDEF0, 258c2ecf20Sopenharmony_ci GPIO_LOS, 268c2ecf20Sopenharmony_ci GPIO_TX_FAULT, 278c2ecf20Sopenharmony_ci GPIO_TX_DISABLE, 288c2ecf20Sopenharmony_ci GPIO_RATE_SELECT, 298c2ecf20Sopenharmony_ci GPIO_MAX, 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci SFP_F_PRESENT = BIT(GPIO_MODDEF0), 328c2ecf20Sopenharmony_ci SFP_F_LOS = BIT(GPIO_LOS), 338c2ecf20Sopenharmony_ci SFP_F_TX_FAULT = BIT(GPIO_TX_FAULT), 348c2ecf20Sopenharmony_ci SFP_F_TX_DISABLE = BIT(GPIO_TX_DISABLE), 358c2ecf20Sopenharmony_ci SFP_F_RATE_SELECT = BIT(GPIO_RATE_SELECT), 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci SFP_E_INSERT = 0, 388c2ecf20Sopenharmony_ci SFP_E_REMOVE, 398c2ecf20Sopenharmony_ci SFP_E_DEV_ATTACH, 408c2ecf20Sopenharmony_ci SFP_E_DEV_DETACH, 418c2ecf20Sopenharmony_ci SFP_E_DEV_DOWN, 428c2ecf20Sopenharmony_ci SFP_E_DEV_UP, 438c2ecf20Sopenharmony_ci SFP_E_TX_FAULT, 448c2ecf20Sopenharmony_ci SFP_E_TX_CLEAR, 458c2ecf20Sopenharmony_ci SFP_E_LOS_HIGH, 468c2ecf20Sopenharmony_ci SFP_E_LOS_LOW, 478c2ecf20Sopenharmony_ci SFP_E_TIMEOUT, 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci SFP_MOD_EMPTY = 0, 508c2ecf20Sopenharmony_ci SFP_MOD_ERROR, 518c2ecf20Sopenharmony_ci SFP_MOD_PROBE, 528c2ecf20Sopenharmony_ci SFP_MOD_WAITDEV, 538c2ecf20Sopenharmony_ci SFP_MOD_HPOWER, 548c2ecf20Sopenharmony_ci SFP_MOD_WAITPWR, 558c2ecf20Sopenharmony_ci SFP_MOD_PRESENT, 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci SFP_DEV_DETACHED = 0, 588c2ecf20Sopenharmony_ci SFP_DEV_DOWN, 598c2ecf20Sopenharmony_ci SFP_DEV_UP, 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci SFP_S_DOWN = 0, 628c2ecf20Sopenharmony_ci SFP_S_FAIL, 638c2ecf20Sopenharmony_ci SFP_S_WAIT, 648c2ecf20Sopenharmony_ci SFP_S_INIT, 658c2ecf20Sopenharmony_ci SFP_S_INIT_PHY, 668c2ecf20Sopenharmony_ci SFP_S_INIT_TX_FAULT, 678c2ecf20Sopenharmony_ci SFP_S_WAIT_LOS, 688c2ecf20Sopenharmony_ci SFP_S_LINK_UP, 698c2ecf20Sopenharmony_ci SFP_S_TX_FAULT, 708c2ecf20Sopenharmony_ci SFP_S_REINIT, 718c2ecf20Sopenharmony_ci SFP_S_TX_DISABLE, 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic const char * const mod_state_strings[] = { 758c2ecf20Sopenharmony_ci [SFP_MOD_EMPTY] = "empty", 768c2ecf20Sopenharmony_ci [SFP_MOD_ERROR] = "error", 778c2ecf20Sopenharmony_ci [SFP_MOD_PROBE] = "probe", 788c2ecf20Sopenharmony_ci [SFP_MOD_WAITDEV] = "waitdev", 798c2ecf20Sopenharmony_ci [SFP_MOD_HPOWER] = "hpower", 808c2ecf20Sopenharmony_ci [SFP_MOD_WAITPWR] = "waitpwr", 818c2ecf20Sopenharmony_ci [SFP_MOD_PRESENT] = "present", 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic const char *mod_state_to_str(unsigned short mod_state) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci if (mod_state >= ARRAY_SIZE(mod_state_strings)) 878c2ecf20Sopenharmony_ci return "Unknown module state"; 888c2ecf20Sopenharmony_ci return mod_state_strings[mod_state]; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic const char * const dev_state_strings[] = { 928c2ecf20Sopenharmony_ci [SFP_DEV_DETACHED] = "detached", 938c2ecf20Sopenharmony_ci [SFP_DEV_DOWN] = "down", 948c2ecf20Sopenharmony_ci [SFP_DEV_UP] = "up", 958c2ecf20Sopenharmony_ci}; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic const char *dev_state_to_str(unsigned short dev_state) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci if (dev_state >= ARRAY_SIZE(dev_state_strings)) 1008c2ecf20Sopenharmony_ci return "Unknown device state"; 1018c2ecf20Sopenharmony_ci return dev_state_strings[dev_state]; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic const char * const event_strings[] = { 1058c2ecf20Sopenharmony_ci [SFP_E_INSERT] = "insert", 1068c2ecf20Sopenharmony_ci [SFP_E_REMOVE] = "remove", 1078c2ecf20Sopenharmony_ci [SFP_E_DEV_ATTACH] = "dev_attach", 1088c2ecf20Sopenharmony_ci [SFP_E_DEV_DETACH] = "dev_detach", 1098c2ecf20Sopenharmony_ci [SFP_E_DEV_DOWN] = "dev_down", 1108c2ecf20Sopenharmony_ci [SFP_E_DEV_UP] = "dev_up", 1118c2ecf20Sopenharmony_ci [SFP_E_TX_FAULT] = "tx_fault", 1128c2ecf20Sopenharmony_ci [SFP_E_TX_CLEAR] = "tx_clear", 1138c2ecf20Sopenharmony_ci [SFP_E_LOS_HIGH] = "los_high", 1148c2ecf20Sopenharmony_ci [SFP_E_LOS_LOW] = "los_low", 1158c2ecf20Sopenharmony_ci [SFP_E_TIMEOUT] = "timeout", 1168c2ecf20Sopenharmony_ci}; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic const char *event_to_str(unsigned short event) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci if (event >= ARRAY_SIZE(event_strings)) 1218c2ecf20Sopenharmony_ci return "Unknown event"; 1228c2ecf20Sopenharmony_ci return event_strings[event]; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic const char * const sm_state_strings[] = { 1268c2ecf20Sopenharmony_ci [SFP_S_DOWN] = "down", 1278c2ecf20Sopenharmony_ci [SFP_S_FAIL] = "fail", 1288c2ecf20Sopenharmony_ci [SFP_S_WAIT] = "wait", 1298c2ecf20Sopenharmony_ci [SFP_S_INIT] = "init", 1308c2ecf20Sopenharmony_ci [SFP_S_INIT_PHY] = "init_phy", 1318c2ecf20Sopenharmony_ci [SFP_S_INIT_TX_FAULT] = "init_tx_fault", 1328c2ecf20Sopenharmony_ci [SFP_S_WAIT_LOS] = "wait_los", 1338c2ecf20Sopenharmony_ci [SFP_S_LINK_UP] = "link_up", 1348c2ecf20Sopenharmony_ci [SFP_S_TX_FAULT] = "tx_fault", 1358c2ecf20Sopenharmony_ci [SFP_S_REINIT] = "reinit", 1368c2ecf20Sopenharmony_ci [SFP_S_TX_DISABLE] = "tx_disable", 1378c2ecf20Sopenharmony_ci}; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic const char *sm_state_to_str(unsigned short sm_state) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci if (sm_state >= ARRAY_SIZE(sm_state_strings)) 1428c2ecf20Sopenharmony_ci return "Unknown state"; 1438c2ecf20Sopenharmony_ci return sm_state_strings[sm_state]; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic const char *gpio_of_names[] = { 1478c2ecf20Sopenharmony_ci "mod-def0", 1488c2ecf20Sopenharmony_ci "los", 1498c2ecf20Sopenharmony_ci "tx-fault", 1508c2ecf20Sopenharmony_ci "tx-disable", 1518c2ecf20Sopenharmony_ci "rate-select0", 1528c2ecf20Sopenharmony_ci}; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic const enum gpiod_flags gpio_flags[] = { 1558c2ecf20Sopenharmony_ci GPIOD_IN, 1568c2ecf20Sopenharmony_ci GPIOD_IN, 1578c2ecf20Sopenharmony_ci GPIOD_IN, 1588c2ecf20Sopenharmony_ci GPIOD_ASIS, 1598c2ecf20Sopenharmony_ci GPIOD_ASIS, 1608c2ecf20Sopenharmony_ci}; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci/* t_start_up (SFF-8431) or t_init (SFF-8472) is the time required for a 1638c2ecf20Sopenharmony_ci * non-cooled module to initialise its laser safety circuitry. We wait 1648c2ecf20Sopenharmony_ci * an initial T_WAIT period before we check the tx fault to give any PHY 1658c2ecf20Sopenharmony_ci * on board (for a copper SFP) time to initialise. 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_ci#define T_WAIT msecs_to_jiffies(50) 1688c2ecf20Sopenharmony_ci#define T_START_UP msecs_to_jiffies(300) 1698c2ecf20Sopenharmony_ci#define T_START_UP_BAD_GPON msecs_to_jiffies(60000) 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/* t_reset is the time required to assert the TX_DISABLE signal to reset 1728c2ecf20Sopenharmony_ci * an indicated TX_FAULT. 1738c2ecf20Sopenharmony_ci */ 1748c2ecf20Sopenharmony_ci#define T_RESET_US 10 1758c2ecf20Sopenharmony_ci#define T_FAULT_RECOVER msecs_to_jiffies(1000) 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci/* N_FAULT_INIT is the number of recovery attempts at module initialisation 1788c2ecf20Sopenharmony_ci * time. If the TX_FAULT signal is not deasserted after this number of 1798c2ecf20Sopenharmony_ci * attempts at clearing it, we decide that the module is faulty. 1808c2ecf20Sopenharmony_ci * N_FAULT is the same but after the module has initialised. 1818c2ecf20Sopenharmony_ci */ 1828c2ecf20Sopenharmony_ci#define N_FAULT_INIT 5 1838c2ecf20Sopenharmony_ci#define N_FAULT 5 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci/* T_PHY_RETRY is the time interval between attempts to probe the PHY. 1868c2ecf20Sopenharmony_ci * R_PHY_RETRY is the number of attempts. 1878c2ecf20Sopenharmony_ci */ 1888c2ecf20Sopenharmony_ci#define T_PHY_RETRY msecs_to_jiffies(50) 1898c2ecf20Sopenharmony_ci#define R_PHY_RETRY 12 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci/* SFP module presence detection is poor: the three MOD DEF signals are 1928c2ecf20Sopenharmony_ci * the same length on the PCB, which means it's possible for MOD DEF 0 to 1938c2ecf20Sopenharmony_ci * connect before the I2C bus on MOD DEF 1/2. 1948c2ecf20Sopenharmony_ci * 1958c2ecf20Sopenharmony_ci * The SFF-8472 specifies t_serial ("Time from power on until module is 1968c2ecf20Sopenharmony_ci * ready for data transmission over the two wire serial bus.") as 300ms. 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci#define T_SERIAL msecs_to_jiffies(300) 1998c2ecf20Sopenharmony_ci#define T_HPOWER_LEVEL msecs_to_jiffies(300) 2008c2ecf20Sopenharmony_ci#define T_PROBE_RETRY_INIT msecs_to_jiffies(100) 2018c2ecf20Sopenharmony_ci#define R_PROBE_RETRY_INIT 10 2028c2ecf20Sopenharmony_ci#define T_PROBE_RETRY_SLOW msecs_to_jiffies(5000) 2038c2ecf20Sopenharmony_ci#define R_PROBE_RETRY_SLOW 12 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci/* SFP modules appear to always have their PHY configured for bus address 2068c2ecf20Sopenharmony_ci * 0x56 (which with mdio-i2c, translates to a PHY address of 22). 2078c2ecf20Sopenharmony_ci */ 2088c2ecf20Sopenharmony_ci#define SFP_PHY_ADDR 22 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci/* SFP_EEPROM_BLOCK_SIZE is the size of data chunk to read the EEPROM 2118c2ecf20Sopenharmony_ci * at a time. Some SFP modules and also some Linux I2C drivers do not like 2128c2ecf20Sopenharmony_ci * reads longer than 16 bytes. 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_ci#define SFP_EEPROM_BLOCK_SIZE 16 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistruct sff_data { 2178c2ecf20Sopenharmony_ci unsigned int gpios; 2188c2ecf20Sopenharmony_ci bool (*module_supported)(const struct sfp_eeprom_id *id); 2198c2ecf20Sopenharmony_ci}; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistruct sfp { 2228c2ecf20Sopenharmony_ci struct device *dev; 2238c2ecf20Sopenharmony_ci struct i2c_adapter *i2c; 2248c2ecf20Sopenharmony_ci struct mii_bus *i2c_mii; 2258c2ecf20Sopenharmony_ci struct sfp_bus *sfp_bus; 2268c2ecf20Sopenharmony_ci struct phy_device *mod_phy; 2278c2ecf20Sopenharmony_ci const struct sff_data *type; 2288c2ecf20Sopenharmony_ci size_t i2c_block_size; 2298c2ecf20Sopenharmony_ci u32 max_power_mW; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci unsigned int (*get_state)(struct sfp *); 2328c2ecf20Sopenharmony_ci void (*set_state)(struct sfp *, unsigned int); 2338c2ecf20Sopenharmony_ci int (*read)(struct sfp *, bool, u8, void *, size_t); 2348c2ecf20Sopenharmony_ci int (*write)(struct sfp *, bool, u8, void *, size_t); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci struct gpio_desc *gpio[GPIO_MAX]; 2378c2ecf20Sopenharmony_ci int gpio_irq[GPIO_MAX]; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci bool need_poll; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci struct mutex st_mutex; /* Protects state */ 2428c2ecf20Sopenharmony_ci unsigned int state_soft_mask; 2438c2ecf20Sopenharmony_ci unsigned int state; 2448c2ecf20Sopenharmony_ci struct delayed_work poll; 2458c2ecf20Sopenharmony_ci struct delayed_work timeout; 2468c2ecf20Sopenharmony_ci struct mutex sm_mutex; /* Protects state machine */ 2478c2ecf20Sopenharmony_ci unsigned char sm_mod_state; 2488c2ecf20Sopenharmony_ci unsigned char sm_mod_tries_init; 2498c2ecf20Sopenharmony_ci unsigned char sm_mod_tries; 2508c2ecf20Sopenharmony_ci unsigned char sm_dev_state; 2518c2ecf20Sopenharmony_ci unsigned short sm_state; 2528c2ecf20Sopenharmony_ci unsigned char sm_fault_retries; 2538c2ecf20Sopenharmony_ci unsigned char sm_phy_retries; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci struct sfp_eeprom_id id; 2568c2ecf20Sopenharmony_ci unsigned int module_power_mW; 2578c2ecf20Sopenharmony_ci unsigned int module_t_start_up; 2588c2ecf20Sopenharmony_ci bool tx_fault_ignore; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_HWMON) 2618c2ecf20Sopenharmony_ci struct sfp_diag diag; 2628c2ecf20Sopenharmony_ci struct delayed_work hwmon_probe; 2638c2ecf20Sopenharmony_ci unsigned int hwmon_tries; 2648c2ecf20Sopenharmony_ci struct device *hwmon_dev; 2658c2ecf20Sopenharmony_ci char *hwmon_name; 2668c2ecf20Sopenharmony_ci#endif 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci}; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic bool sff_module_supported(const struct sfp_eeprom_id *id) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci return id->base.phys_id == SFF8024_ID_SFF_8472 && 2738c2ecf20Sopenharmony_ci id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic const struct sff_data sff_data = { 2778c2ecf20Sopenharmony_ci .gpios = SFP_F_LOS | SFP_F_TX_FAULT | SFP_F_TX_DISABLE, 2788c2ecf20Sopenharmony_ci .module_supported = sff_module_supported, 2798c2ecf20Sopenharmony_ci}; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic bool sfp_module_supported(const struct sfp_eeprom_id *id) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci if (id->base.phys_id == SFF8024_ID_SFP && 2848c2ecf20Sopenharmony_ci id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP) 2858c2ecf20Sopenharmony_ci return true; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* SFP GPON module Ubiquiti U-Fiber Instant has in its EEPROM stored 2888c2ecf20Sopenharmony_ci * phys id SFF instead of SFP. Therefore mark this module explicitly 2898c2ecf20Sopenharmony_ci * as supported based on vendor name and pn match. 2908c2ecf20Sopenharmony_ci */ 2918c2ecf20Sopenharmony_ci if (id->base.phys_id == SFF8024_ID_SFF_8472 && 2928c2ecf20Sopenharmony_ci id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP && 2938c2ecf20Sopenharmony_ci !memcmp(id->base.vendor_name, "UBNT ", 16) && 2948c2ecf20Sopenharmony_ci !memcmp(id->base.vendor_pn, "UF-INSTANT ", 16)) 2958c2ecf20Sopenharmony_ci return true; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci return false; 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic const struct sff_data sfp_data = { 3018c2ecf20Sopenharmony_ci .gpios = SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT | 3028c2ecf20Sopenharmony_ci SFP_F_TX_DISABLE | SFP_F_RATE_SELECT, 3038c2ecf20Sopenharmony_ci .module_supported = sfp_module_supported, 3048c2ecf20Sopenharmony_ci}; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic const struct of_device_id sfp_of_match[] = { 3078c2ecf20Sopenharmony_ci { .compatible = "sff,sff", .data = &sff_data, }, 3088c2ecf20Sopenharmony_ci { .compatible = "sff,sfp", .data = &sfp_data, }, 3098c2ecf20Sopenharmony_ci { }, 3108c2ecf20Sopenharmony_ci}; 3118c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sfp_of_match); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic unsigned long poll_jiffies; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic unsigned int sfp_gpio_get_state(struct sfp *sfp) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci unsigned int i, state, v; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci for (i = state = 0; i < GPIO_MAX; i++) { 3208c2ecf20Sopenharmony_ci if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i]) 3218c2ecf20Sopenharmony_ci continue; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci v = gpiod_get_value_cansleep(sfp->gpio[i]); 3248c2ecf20Sopenharmony_ci if (v) 3258c2ecf20Sopenharmony_ci state |= BIT(i); 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci return state; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic unsigned int sff_gpio_get_state(struct sfp *sfp) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci return sfp_gpio_get_state(sfp) | SFP_F_PRESENT; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic void sfp_gpio_set_state(struct sfp *sfp, unsigned int state) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci if (state & SFP_F_PRESENT) { 3398c2ecf20Sopenharmony_ci /* If the module is present, drive the signals */ 3408c2ecf20Sopenharmony_ci if (sfp->gpio[GPIO_TX_DISABLE]) 3418c2ecf20Sopenharmony_ci gpiod_direction_output(sfp->gpio[GPIO_TX_DISABLE], 3428c2ecf20Sopenharmony_ci state & SFP_F_TX_DISABLE); 3438c2ecf20Sopenharmony_ci if (state & SFP_F_RATE_SELECT) 3448c2ecf20Sopenharmony_ci gpiod_direction_output(sfp->gpio[GPIO_RATE_SELECT], 3458c2ecf20Sopenharmony_ci state & SFP_F_RATE_SELECT); 3468c2ecf20Sopenharmony_ci } else { 3478c2ecf20Sopenharmony_ci /* Otherwise, let them float to the pull-ups */ 3488c2ecf20Sopenharmony_ci if (sfp->gpio[GPIO_TX_DISABLE]) 3498c2ecf20Sopenharmony_ci gpiod_direction_input(sfp->gpio[GPIO_TX_DISABLE]); 3508c2ecf20Sopenharmony_ci if (state & SFP_F_RATE_SELECT) 3518c2ecf20Sopenharmony_ci gpiod_direction_input(sfp->gpio[GPIO_RATE_SELECT]); 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic int sfp_i2c_read(struct sfp *sfp, bool a2, u8 dev_addr, void *buf, 3568c2ecf20Sopenharmony_ci size_t len) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct i2c_msg msgs[2]; 3598c2ecf20Sopenharmony_ci u8 bus_addr = a2 ? 0x51 : 0x50; 3608c2ecf20Sopenharmony_ci size_t block_size = sfp->i2c_block_size; 3618c2ecf20Sopenharmony_ci size_t this_len; 3628c2ecf20Sopenharmony_ci int ret; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci msgs[0].addr = bus_addr; 3658c2ecf20Sopenharmony_ci msgs[0].flags = 0; 3668c2ecf20Sopenharmony_ci msgs[0].len = 1; 3678c2ecf20Sopenharmony_ci msgs[0].buf = &dev_addr; 3688c2ecf20Sopenharmony_ci msgs[1].addr = bus_addr; 3698c2ecf20Sopenharmony_ci msgs[1].flags = I2C_M_RD; 3708c2ecf20Sopenharmony_ci msgs[1].len = len; 3718c2ecf20Sopenharmony_ci msgs[1].buf = buf; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci while (len) { 3748c2ecf20Sopenharmony_ci this_len = len; 3758c2ecf20Sopenharmony_ci if (this_len > block_size) 3768c2ecf20Sopenharmony_ci this_len = block_size; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci msgs[1].len = this_len; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci ret = i2c_transfer(sfp->i2c, msgs, ARRAY_SIZE(msgs)); 3818c2ecf20Sopenharmony_ci if (ret < 0) 3828c2ecf20Sopenharmony_ci return ret; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (ret != ARRAY_SIZE(msgs)) 3858c2ecf20Sopenharmony_ci break; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci msgs[1].buf += this_len; 3888c2ecf20Sopenharmony_ci dev_addr += this_len; 3898c2ecf20Sopenharmony_ci len -= this_len; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci return msgs[1].buf - (u8 *)buf; 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic int sfp_i2c_write(struct sfp *sfp, bool a2, u8 dev_addr, void *buf, 3968c2ecf20Sopenharmony_ci size_t len) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci struct i2c_msg msgs[1]; 3998c2ecf20Sopenharmony_ci u8 bus_addr = a2 ? 0x51 : 0x50; 4008c2ecf20Sopenharmony_ci int ret; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci msgs[0].addr = bus_addr; 4038c2ecf20Sopenharmony_ci msgs[0].flags = 0; 4048c2ecf20Sopenharmony_ci msgs[0].len = 1 + len; 4058c2ecf20Sopenharmony_ci msgs[0].buf = kmalloc(1 + len, GFP_KERNEL); 4068c2ecf20Sopenharmony_ci if (!msgs[0].buf) 4078c2ecf20Sopenharmony_ci return -ENOMEM; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci msgs[0].buf[0] = dev_addr; 4108c2ecf20Sopenharmony_ci memcpy(&msgs[0].buf[1], buf, len); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci ret = i2c_transfer(sfp->i2c, msgs, ARRAY_SIZE(msgs)); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci kfree(msgs[0].buf); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (ret < 0) 4178c2ecf20Sopenharmony_ci return ret; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci return ret == ARRAY_SIZE(msgs) ? len : 0; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci struct mii_bus *i2c_mii; 4258c2ecf20Sopenharmony_ci int ret; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci if (!i2c_check_functionality(i2c, I2C_FUNC_I2C)) 4288c2ecf20Sopenharmony_ci return -EINVAL; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci sfp->i2c = i2c; 4318c2ecf20Sopenharmony_ci sfp->read = sfp_i2c_read; 4328c2ecf20Sopenharmony_ci sfp->write = sfp_i2c_write; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci i2c_mii = mdio_i2c_alloc(sfp->dev, i2c); 4358c2ecf20Sopenharmony_ci if (IS_ERR(i2c_mii)) 4368c2ecf20Sopenharmony_ci return PTR_ERR(i2c_mii); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci i2c_mii->name = "SFP I2C Bus"; 4398c2ecf20Sopenharmony_ci i2c_mii->phy_mask = ~0; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci ret = mdiobus_register(i2c_mii); 4428c2ecf20Sopenharmony_ci if (ret < 0) { 4438c2ecf20Sopenharmony_ci mdiobus_free(i2c_mii); 4448c2ecf20Sopenharmony_ci return ret; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci sfp->i2c_mii = i2c_mii; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci return 0; 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci/* Interface */ 4538c2ecf20Sopenharmony_cistatic int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci return sfp->read(sfp, a2, addr, buf, len); 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic int sfp_write(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci return sfp->write(sfp, a2, addr, buf, len); 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic unsigned int sfp_soft_get_state(struct sfp *sfp) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci unsigned int state = 0; 4668c2ecf20Sopenharmony_ci u8 status; 4678c2ecf20Sopenharmony_ci int ret; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci ret = sfp_read(sfp, true, SFP_STATUS, &status, sizeof(status)); 4708c2ecf20Sopenharmony_ci if (ret == sizeof(status)) { 4718c2ecf20Sopenharmony_ci if (status & SFP_STATUS_RX_LOS) 4728c2ecf20Sopenharmony_ci state |= SFP_F_LOS; 4738c2ecf20Sopenharmony_ci if (status & SFP_STATUS_TX_FAULT) 4748c2ecf20Sopenharmony_ci state |= SFP_F_TX_FAULT; 4758c2ecf20Sopenharmony_ci } else { 4768c2ecf20Sopenharmony_ci dev_err_ratelimited(sfp->dev, 4778c2ecf20Sopenharmony_ci "failed to read SFP soft status: %d\n", 4788c2ecf20Sopenharmony_ci ret); 4798c2ecf20Sopenharmony_ci /* Preserve the current state */ 4808c2ecf20Sopenharmony_ci state = sfp->state; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci return state & sfp->state_soft_mask; 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic void sfp_soft_set_state(struct sfp *sfp, unsigned int state) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci u8 status; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (sfp_read(sfp, true, SFP_STATUS, &status, sizeof(status)) == 4918c2ecf20Sopenharmony_ci sizeof(status)) { 4928c2ecf20Sopenharmony_ci if (state & SFP_F_TX_DISABLE) 4938c2ecf20Sopenharmony_ci status |= SFP_STATUS_TX_DISABLE_FORCE; 4948c2ecf20Sopenharmony_ci else 4958c2ecf20Sopenharmony_ci status &= ~SFP_STATUS_TX_DISABLE_FORCE; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci sfp_write(sfp, true, SFP_STATUS, &status, sizeof(status)); 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic void sfp_soft_start_poll(struct sfp *sfp) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci const struct sfp_eeprom_id *id = &sfp->id; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci sfp->state_soft_mask = 0; 5068c2ecf20Sopenharmony_ci if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_DISABLE && 5078c2ecf20Sopenharmony_ci !sfp->gpio[GPIO_TX_DISABLE]) 5088c2ecf20Sopenharmony_ci sfp->state_soft_mask |= SFP_F_TX_DISABLE; 5098c2ecf20Sopenharmony_ci if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_FAULT && 5108c2ecf20Sopenharmony_ci !sfp->gpio[GPIO_TX_FAULT]) 5118c2ecf20Sopenharmony_ci sfp->state_soft_mask |= SFP_F_TX_FAULT; 5128c2ecf20Sopenharmony_ci if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS && 5138c2ecf20Sopenharmony_ci !sfp->gpio[GPIO_LOS]) 5148c2ecf20Sopenharmony_ci sfp->state_soft_mask |= SFP_F_LOS; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) && 5178c2ecf20Sopenharmony_ci !sfp->need_poll) 5188c2ecf20Sopenharmony_ci mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic void sfp_soft_stop_poll(struct sfp *sfp) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci sfp->state_soft_mask = 0; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic unsigned int sfp_get_state(struct sfp *sfp) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci unsigned int state = sfp->get_state(sfp); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (state & SFP_F_PRESENT && 5318c2ecf20Sopenharmony_ci sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT)) 5328c2ecf20Sopenharmony_ci state |= sfp_soft_get_state(sfp); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci return state; 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic void sfp_set_state(struct sfp *sfp, unsigned int state) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci sfp->set_state(sfp, state); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci if (state & SFP_F_PRESENT && 5428c2ecf20Sopenharmony_ci sfp->state_soft_mask & SFP_F_TX_DISABLE) 5438c2ecf20Sopenharmony_ci sfp_soft_set_state(sfp, state); 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic unsigned int sfp_check(void *buf, size_t len) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci u8 *p, check; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci for (p = buf, check = 0; len; p++, len--) 5518c2ecf20Sopenharmony_ci check += *p; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci return check; 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci/* hwmon */ 5578c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_HWMON) 5588c2ecf20Sopenharmony_cistatic umode_t sfp_hwmon_is_visible(const void *data, 5598c2ecf20Sopenharmony_ci enum hwmon_sensor_types type, 5608c2ecf20Sopenharmony_ci u32 attr, int channel) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci const struct sfp *sfp = data; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci switch (type) { 5658c2ecf20Sopenharmony_ci case hwmon_temp: 5668c2ecf20Sopenharmony_ci switch (attr) { 5678c2ecf20Sopenharmony_ci case hwmon_temp_min_alarm: 5688c2ecf20Sopenharmony_ci case hwmon_temp_max_alarm: 5698c2ecf20Sopenharmony_ci case hwmon_temp_lcrit_alarm: 5708c2ecf20Sopenharmony_ci case hwmon_temp_crit_alarm: 5718c2ecf20Sopenharmony_ci case hwmon_temp_min: 5728c2ecf20Sopenharmony_ci case hwmon_temp_max: 5738c2ecf20Sopenharmony_ci case hwmon_temp_lcrit: 5748c2ecf20Sopenharmony_ci case hwmon_temp_crit: 5758c2ecf20Sopenharmony_ci if (!(sfp->id.ext.enhopts & SFP_ENHOPTS_ALARMWARN)) 5768c2ecf20Sopenharmony_ci return 0; 5778c2ecf20Sopenharmony_ci fallthrough; 5788c2ecf20Sopenharmony_ci case hwmon_temp_input: 5798c2ecf20Sopenharmony_ci case hwmon_temp_label: 5808c2ecf20Sopenharmony_ci return 0444; 5818c2ecf20Sopenharmony_ci default: 5828c2ecf20Sopenharmony_ci return 0; 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci case hwmon_in: 5858c2ecf20Sopenharmony_ci switch (attr) { 5868c2ecf20Sopenharmony_ci case hwmon_in_min_alarm: 5878c2ecf20Sopenharmony_ci case hwmon_in_max_alarm: 5888c2ecf20Sopenharmony_ci case hwmon_in_lcrit_alarm: 5898c2ecf20Sopenharmony_ci case hwmon_in_crit_alarm: 5908c2ecf20Sopenharmony_ci case hwmon_in_min: 5918c2ecf20Sopenharmony_ci case hwmon_in_max: 5928c2ecf20Sopenharmony_ci case hwmon_in_lcrit: 5938c2ecf20Sopenharmony_ci case hwmon_in_crit: 5948c2ecf20Sopenharmony_ci if (!(sfp->id.ext.enhopts & SFP_ENHOPTS_ALARMWARN)) 5958c2ecf20Sopenharmony_ci return 0; 5968c2ecf20Sopenharmony_ci fallthrough; 5978c2ecf20Sopenharmony_ci case hwmon_in_input: 5988c2ecf20Sopenharmony_ci case hwmon_in_label: 5998c2ecf20Sopenharmony_ci return 0444; 6008c2ecf20Sopenharmony_ci default: 6018c2ecf20Sopenharmony_ci return 0; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci case hwmon_curr: 6048c2ecf20Sopenharmony_ci switch (attr) { 6058c2ecf20Sopenharmony_ci case hwmon_curr_min_alarm: 6068c2ecf20Sopenharmony_ci case hwmon_curr_max_alarm: 6078c2ecf20Sopenharmony_ci case hwmon_curr_lcrit_alarm: 6088c2ecf20Sopenharmony_ci case hwmon_curr_crit_alarm: 6098c2ecf20Sopenharmony_ci case hwmon_curr_min: 6108c2ecf20Sopenharmony_ci case hwmon_curr_max: 6118c2ecf20Sopenharmony_ci case hwmon_curr_lcrit: 6128c2ecf20Sopenharmony_ci case hwmon_curr_crit: 6138c2ecf20Sopenharmony_ci if (!(sfp->id.ext.enhopts & SFP_ENHOPTS_ALARMWARN)) 6148c2ecf20Sopenharmony_ci return 0; 6158c2ecf20Sopenharmony_ci fallthrough; 6168c2ecf20Sopenharmony_ci case hwmon_curr_input: 6178c2ecf20Sopenharmony_ci case hwmon_curr_label: 6188c2ecf20Sopenharmony_ci return 0444; 6198c2ecf20Sopenharmony_ci default: 6208c2ecf20Sopenharmony_ci return 0; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci case hwmon_power: 6238c2ecf20Sopenharmony_ci /* External calibration of receive power requires 6248c2ecf20Sopenharmony_ci * floating point arithmetic. Doing that in the kernel 6258c2ecf20Sopenharmony_ci * is not easy, so just skip it. If the module does 6268c2ecf20Sopenharmony_ci * not require external calibration, we can however 6278c2ecf20Sopenharmony_ci * show receiver power, since FP is then not needed. 6288c2ecf20Sopenharmony_ci */ 6298c2ecf20Sopenharmony_ci if (sfp->id.ext.diagmon & SFP_DIAGMON_EXT_CAL && 6308c2ecf20Sopenharmony_ci channel == 1) 6318c2ecf20Sopenharmony_ci return 0; 6328c2ecf20Sopenharmony_ci switch (attr) { 6338c2ecf20Sopenharmony_ci case hwmon_power_min_alarm: 6348c2ecf20Sopenharmony_ci case hwmon_power_max_alarm: 6358c2ecf20Sopenharmony_ci case hwmon_power_lcrit_alarm: 6368c2ecf20Sopenharmony_ci case hwmon_power_crit_alarm: 6378c2ecf20Sopenharmony_ci case hwmon_power_min: 6388c2ecf20Sopenharmony_ci case hwmon_power_max: 6398c2ecf20Sopenharmony_ci case hwmon_power_lcrit: 6408c2ecf20Sopenharmony_ci case hwmon_power_crit: 6418c2ecf20Sopenharmony_ci if (!(sfp->id.ext.enhopts & SFP_ENHOPTS_ALARMWARN)) 6428c2ecf20Sopenharmony_ci return 0; 6438c2ecf20Sopenharmony_ci fallthrough; 6448c2ecf20Sopenharmony_ci case hwmon_power_input: 6458c2ecf20Sopenharmony_ci case hwmon_power_label: 6468c2ecf20Sopenharmony_ci return 0444; 6478c2ecf20Sopenharmony_ci default: 6488c2ecf20Sopenharmony_ci return 0; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci default: 6518c2ecf20Sopenharmony_ci return 0; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci} 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_cistatic int sfp_hwmon_read_sensor(struct sfp *sfp, int reg, long *value) 6568c2ecf20Sopenharmony_ci{ 6578c2ecf20Sopenharmony_ci __be16 val; 6588c2ecf20Sopenharmony_ci int err; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, reg, &val, sizeof(val)); 6618c2ecf20Sopenharmony_ci if (err < 0) 6628c2ecf20Sopenharmony_ci return err; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci *value = be16_to_cpu(val); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci return 0; 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_cistatic void sfp_hwmon_to_rx_power(long *value) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci *value = DIV_ROUND_CLOSEST(*value, 10); 6728c2ecf20Sopenharmony_ci} 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_cistatic void sfp_hwmon_calibrate(struct sfp *sfp, unsigned int slope, int offset, 6758c2ecf20Sopenharmony_ci long *value) 6768c2ecf20Sopenharmony_ci{ 6778c2ecf20Sopenharmony_ci if (sfp->id.ext.diagmon & SFP_DIAGMON_EXT_CAL) 6788c2ecf20Sopenharmony_ci *value = DIV_ROUND_CLOSEST(*value * slope, 256) + offset; 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_cistatic void sfp_hwmon_calibrate_temp(struct sfp *sfp, long *value) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci sfp_hwmon_calibrate(sfp, be16_to_cpu(sfp->diag.cal_t_slope), 6848c2ecf20Sopenharmony_ci be16_to_cpu(sfp->diag.cal_t_offset), value); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci if (*value >= 0x8000) 6878c2ecf20Sopenharmony_ci *value -= 0x10000; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci *value = DIV_ROUND_CLOSEST(*value * 1000, 256); 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cistatic void sfp_hwmon_calibrate_vcc(struct sfp *sfp, long *value) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci sfp_hwmon_calibrate(sfp, be16_to_cpu(sfp->diag.cal_v_slope), 6958c2ecf20Sopenharmony_ci be16_to_cpu(sfp->diag.cal_v_offset), value); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci *value = DIV_ROUND_CLOSEST(*value, 10); 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cistatic void sfp_hwmon_calibrate_bias(struct sfp *sfp, long *value) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci sfp_hwmon_calibrate(sfp, be16_to_cpu(sfp->diag.cal_txi_slope), 7038c2ecf20Sopenharmony_ci be16_to_cpu(sfp->diag.cal_txi_offset), value); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci *value = DIV_ROUND_CLOSEST(*value, 500); 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic void sfp_hwmon_calibrate_tx_power(struct sfp *sfp, long *value) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci sfp_hwmon_calibrate(sfp, be16_to_cpu(sfp->diag.cal_txpwr_slope), 7118c2ecf20Sopenharmony_ci be16_to_cpu(sfp->diag.cal_txpwr_offset), value); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci *value = DIV_ROUND_CLOSEST(*value, 10); 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_cistatic int sfp_hwmon_read_temp(struct sfp *sfp, int reg, long *value) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci int err; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci err = sfp_hwmon_read_sensor(sfp, reg, value); 7218c2ecf20Sopenharmony_ci if (err < 0) 7228c2ecf20Sopenharmony_ci return err; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci sfp_hwmon_calibrate_temp(sfp, value); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci return 0; 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cistatic int sfp_hwmon_read_vcc(struct sfp *sfp, int reg, long *value) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci int err; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci err = sfp_hwmon_read_sensor(sfp, reg, value); 7348c2ecf20Sopenharmony_ci if (err < 0) 7358c2ecf20Sopenharmony_ci return err; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci sfp_hwmon_calibrate_vcc(sfp, value); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci return 0; 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_cistatic int sfp_hwmon_read_bias(struct sfp *sfp, int reg, long *value) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci int err; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci err = sfp_hwmon_read_sensor(sfp, reg, value); 7478c2ecf20Sopenharmony_ci if (err < 0) 7488c2ecf20Sopenharmony_ci return err; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci sfp_hwmon_calibrate_bias(sfp, value); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci return 0; 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_cistatic int sfp_hwmon_read_tx_power(struct sfp *sfp, int reg, long *value) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci int err; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci err = sfp_hwmon_read_sensor(sfp, reg, value); 7608c2ecf20Sopenharmony_ci if (err < 0) 7618c2ecf20Sopenharmony_ci return err; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci sfp_hwmon_calibrate_tx_power(sfp, value); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci return 0; 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_cistatic int sfp_hwmon_read_rx_power(struct sfp *sfp, int reg, long *value) 7698c2ecf20Sopenharmony_ci{ 7708c2ecf20Sopenharmony_ci int err; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci err = sfp_hwmon_read_sensor(sfp, reg, value); 7738c2ecf20Sopenharmony_ci if (err < 0) 7748c2ecf20Sopenharmony_ci return err; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci sfp_hwmon_to_rx_power(value); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci return 0; 7798c2ecf20Sopenharmony_ci} 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_cistatic int sfp_hwmon_temp(struct sfp *sfp, u32 attr, long *value) 7828c2ecf20Sopenharmony_ci{ 7838c2ecf20Sopenharmony_ci u8 status; 7848c2ecf20Sopenharmony_ci int err; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci switch (attr) { 7878c2ecf20Sopenharmony_ci case hwmon_temp_input: 7888c2ecf20Sopenharmony_ci return sfp_hwmon_read_temp(sfp, SFP_TEMP, value); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci case hwmon_temp_lcrit: 7918c2ecf20Sopenharmony_ci *value = be16_to_cpu(sfp->diag.temp_low_alarm); 7928c2ecf20Sopenharmony_ci sfp_hwmon_calibrate_temp(sfp, value); 7938c2ecf20Sopenharmony_ci return 0; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci case hwmon_temp_min: 7968c2ecf20Sopenharmony_ci *value = be16_to_cpu(sfp->diag.temp_low_warn); 7978c2ecf20Sopenharmony_ci sfp_hwmon_calibrate_temp(sfp, value); 7988c2ecf20Sopenharmony_ci return 0; 7998c2ecf20Sopenharmony_ci case hwmon_temp_max: 8008c2ecf20Sopenharmony_ci *value = be16_to_cpu(sfp->diag.temp_high_warn); 8018c2ecf20Sopenharmony_ci sfp_hwmon_calibrate_temp(sfp, value); 8028c2ecf20Sopenharmony_ci return 0; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci case hwmon_temp_crit: 8058c2ecf20Sopenharmony_ci *value = be16_to_cpu(sfp->diag.temp_high_alarm); 8068c2ecf20Sopenharmony_ci sfp_hwmon_calibrate_temp(sfp, value); 8078c2ecf20Sopenharmony_ci return 0; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci case hwmon_temp_lcrit_alarm: 8108c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_ALARM0, &status, sizeof(status)); 8118c2ecf20Sopenharmony_ci if (err < 0) 8128c2ecf20Sopenharmony_ci return err; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci *value = !!(status & SFP_ALARM0_TEMP_LOW); 8158c2ecf20Sopenharmony_ci return 0; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci case hwmon_temp_min_alarm: 8188c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_WARN0, &status, sizeof(status)); 8198c2ecf20Sopenharmony_ci if (err < 0) 8208c2ecf20Sopenharmony_ci return err; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci *value = !!(status & SFP_WARN0_TEMP_LOW); 8238c2ecf20Sopenharmony_ci return 0; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci case hwmon_temp_max_alarm: 8268c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_WARN0, &status, sizeof(status)); 8278c2ecf20Sopenharmony_ci if (err < 0) 8288c2ecf20Sopenharmony_ci return err; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci *value = !!(status & SFP_WARN0_TEMP_HIGH); 8318c2ecf20Sopenharmony_ci return 0; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci case hwmon_temp_crit_alarm: 8348c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_ALARM0, &status, sizeof(status)); 8358c2ecf20Sopenharmony_ci if (err < 0) 8368c2ecf20Sopenharmony_ci return err; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci *value = !!(status & SFP_ALARM0_TEMP_HIGH); 8398c2ecf20Sopenharmony_ci return 0; 8408c2ecf20Sopenharmony_ci default: 8418c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_cistatic int sfp_hwmon_vcc(struct sfp *sfp, u32 attr, long *value) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci u8 status; 8508c2ecf20Sopenharmony_ci int err; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci switch (attr) { 8538c2ecf20Sopenharmony_ci case hwmon_in_input: 8548c2ecf20Sopenharmony_ci return sfp_hwmon_read_vcc(sfp, SFP_VCC, value); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci case hwmon_in_lcrit: 8578c2ecf20Sopenharmony_ci *value = be16_to_cpu(sfp->diag.volt_low_alarm); 8588c2ecf20Sopenharmony_ci sfp_hwmon_calibrate_vcc(sfp, value); 8598c2ecf20Sopenharmony_ci return 0; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci case hwmon_in_min: 8628c2ecf20Sopenharmony_ci *value = be16_to_cpu(sfp->diag.volt_low_warn); 8638c2ecf20Sopenharmony_ci sfp_hwmon_calibrate_vcc(sfp, value); 8648c2ecf20Sopenharmony_ci return 0; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci case hwmon_in_max: 8678c2ecf20Sopenharmony_ci *value = be16_to_cpu(sfp->diag.volt_high_warn); 8688c2ecf20Sopenharmony_ci sfp_hwmon_calibrate_vcc(sfp, value); 8698c2ecf20Sopenharmony_ci return 0; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci case hwmon_in_crit: 8728c2ecf20Sopenharmony_ci *value = be16_to_cpu(sfp->diag.volt_high_alarm); 8738c2ecf20Sopenharmony_ci sfp_hwmon_calibrate_vcc(sfp, value); 8748c2ecf20Sopenharmony_ci return 0; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci case hwmon_in_lcrit_alarm: 8778c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_ALARM0, &status, sizeof(status)); 8788c2ecf20Sopenharmony_ci if (err < 0) 8798c2ecf20Sopenharmony_ci return err; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci *value = !!(status & SFP_ALARM0_VCC_LOW); 8828c2ecf20Sopenharmony_ci return 0; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci case hwmon_in_min_alarm: 8858c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_WARN0, &status, sizeof(status)); 8868c2ecf20Sopenharmony_ci if (err < 0) 8878c2ecf20Sopenharmony_ci return err; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci *value = !!(status & SFP_WARN0_VCC_LOW); 8908c2ecf20Sopenharmony_ci return 0; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci case hwmon_in_max_alarm: 8938c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_WARN0, &status, sizeof(status)); 8948c2ecf20Sopenharmony_ci if (err < 0) 8958c2ecf20Sopenharmony_ci return err; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci *value = !!(status & SFP_WARN0_VCC_HIGH); 8988c2ecf20Sopenharmony_ci return 0; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci case hwmon_in_crit_alarm: 9018c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_ALARM0, &status, sizeof(status)); 9028c2ecf20Sopenharmony_ci if (err < 0) 9038c2ecf20Sopenharmony_ci return err; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci *value = !!(status & SFP_ALARM0_VCC_HIGH); 9068c2ecf20Sopenharmony_ci return 0; 9078c2ecf20Sopenharmony_ci default: 9088c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic int sfp_hwmon_bias(struct sfp *sfp, u32 attr, long *value) 9158c2ecf20Sopenharmony_ci{ 9168c2ecf20Sopenharmony_ci u8 status; 9178c2ecf20Sopenharmony_ci int err; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci switch (attr) { 9208c2ecf20Sopenharmony_ci case hwmon_curr_input: 9218c2ecf20Sopenharmony_ci return sfp_hwmon_read_bias(sfp, SFP_TX_BIAS, value); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci case hwmon_curr_lcrit: 9248c2ecf20Sopenharmony_ci *value = be16_to_cpu(sfp->diag.bias_low_alarm); 9258c2ecf20Sopenharmony_ci sfp_hwmon_calibrate_bias(sfp, value); 9268c2ecf20Sopenharmony_ci return 0; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci case hwmon_curr_min: 9298c2ecf20Sopenharmony_ci *value = be16_to_cpu(sfp->diag.bias_low_warn); 9308c2ecf20Sopenharmony_ci sfp_hwmon_calibrate_bias(sfp, value); 9318c2ecf20Sopenharmony_ci return 0; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci case hwmon_curr_max: 9348c2ecf20Sopenharmony_ci *value = be16_to_cpu(sfp->diag.bias_high_warn); 9358c2ecf20Sopenharmony_ci sfp_hwmon_calibrate_bias(sfp, value); 9368c2ecf20Sopenharmony_ci return 0; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci case hwmon_curr_crit: 9398c2ecf20Sopenharmony_ci *value = be16_to_cpu(sfp->diag.bias_high_alarm); 9408c2ecf20Sopenharmony_ci sfp_hwmon_calibrate_bias(sfp, value); 9418c2ecf20Sopenharmony_ci return 0; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci case hwmon_curr_lcrit_alarm: 9448c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_ALARM0, &status, sizeof(status)); 9458c2ecf20Sopenharmony_ci if (err < 0) 9468c2ecf20Sopenharmony_ci return err; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci *value = !!(status & SFP_ALARM0_TX_BIAS_LOW); 9498c2ecf20Sopenharmony_ci return 0; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci case hwmon_curr_min_alarm: 9528c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_WARN0, &status, sizeof(status)); 9538c2ecf20Sopenharmony_ci if (err < 0) 9548c2ecf20Sopenharmony_ci return err; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci *value = !!(status & SFP_WARN0_TX_BIAS_LOW); 9578c2ecf20Sopenharmony_ci return 0; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci case hwmon_curr_max_alarm: 9608c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_WARN0, &status, sizeof(status)); 9618c2ecf20Sopenharmony_ci if (err < 0) 9628c2ecf20Sopenharmony_ci return err; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci *value = !!(status & SFP_WARN0_TX_BIAS_HIGH); 9658c2ecf20Sopenharmony_ci return 0; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci case hwmon_curr_crit_alarm: 9688c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_ALARM0, &status, sizeof(status)); 9698c2ecf20Sopenharmony_ci if (err < 0) 9708c2ecf20Sopenharmony_ci return err; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci *value = !!(status & SFP_ALARM0_TX_BIAS_HIGH); 9738c2ecf20Sopenharmony_ci return 0; 9748c2ecf20Sopenharmony_ci default: 9758c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9798c2ecf20Sopenharmony_ci} 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_cistatic int sfp_hwmon_tx_power(struct sfp *sfp, u32 attr, long *value) 9828c2ecf20Sopenharmony_ci{ 9838c2ecf20Sopenharmony_ci u8 status; 9848c2ecf20Sopenharmony_ci int err; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci switch (attr) { 9878c2ecf20Sopenharmony_ci case hwmon_power_input: 9888c2ecf20Sopenharmony_ci return sfp_hwmon_read_tx_power(sfp, SFP_TX_POWER, value); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci case hwmon_power_lcrit: 9918c2ecf20Sopenharmony_ci *value = be16_to_cpu(sfp->diag.txpwr_low_alarm); 9928c2ecf20Sopenharmony_ci sfp_hwmon_calibrate_tx_power(sfp, value); 9938c2ecf20Sopenharmony_ci return 0; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci case hwmon_power_min: 9968c2ecf20Sopenharmony_ci *value = be16_to_cpu(sfp->diag.txpwr_low_warn); 9978c2ecf20Sopenharmony_ci sfp_hwmon_calibrate_tx_power(sfp, value); 9988c2ecf20Sopenharmony_ci return 0; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci case hwmon_power_max: 10018c2ecf20Sopenharmony_ci *value = be16_to_cpu(sfp->diag.txpwr_high_warn); 10028c2ecf20Sopenharmony_ci sfp_hwmon_calibrate_tx_power(sfp, value); 10038c2ecf20Sopenharmony_ci return 0; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci case hwmon_power_crit: 10068c2ecf20Sopenharmony_ci *value = be16_to_cpu(sfp->diag.txpwr_high_alarm); 10078c2ecf20Sopenharmony_ci sfp_hwmon_calibrate_tx_power(sfp, value); 10088c2ecf20Sopenharmony_ci return 0; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci case hwmon_power_lcrit_alarm: 10118c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_ALARM0, &status, sizeof(status)); 10128c2ecf20Sopenharmony_ci if (err < 0) 10138c2ecf20Sopenharmony_ci return err; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci *value = !!(status & SFP_ALARM0_TXPWR_LOW); 10168c2ecf20Sopenharmony_ci return 0; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci case hwmon_power_min_alarm: 10198c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_WARN0, &status, sizeof(status)); 10208c2ecf20Sopenharmony_ci if (err < 0) 10218c2ecf20Sopenharmony_ci return err; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci *value = !!(status & SFP_WARN0_TXPWR_LOW); 10248c2ecf20Sopenharmony_ci return 0; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci case hwmon_power_max_alarm: 10278c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_WARN0, &status, sizeof(status)); 10288c2ecf20Sopenharmony_ci if (err < 0) 10298c2ecf20Sopenharmony_ci return err; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci *value = !!(status & SFP_WARN0_TXPWR_HIGH); 10328c2ecf20Sopenharmony_ci return 0; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci case hwmon_power_crit_alarm: 10358c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_ALARM0, &status, sizeof(status)); 10368c2ecf20Sopenharmony_ci if (err < 0) 10378c2ecf20Sopenharmony_ci return err; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci *value = !!(status & SFP_ALARM0_TXPWR_HIGH); 10408c2ecf20Sopenharmony_ci return 0; 10418c2ecf20Sopenharmony_ci default: 10428c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 10438c2ecf20Sopenharmony_ci } 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 10468c2ecf20Sopenharmony_ci} 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_cistatic int sfp_hwmon_rx_power(struct sfp *sfp, u32 attr, long *value) 10498c2ecf20Sopenharmony_ci{ 10508c2ecf20Sopenharmony_ci u8 status; 10518c2ecf20Sopenharmony_ci int err; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci switch (attr) { 10548c2ecf20Sopenharmony_ci case hwmon_power_input: 10558c2ecf20Sopenharmony_ci return sfp_hwmon_read_rx_power(sfp, SFP_RX_POWER, value); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci case hwmon_power_lcrit: 10588c2ecf20Sopenharmony_ci *value = be16_to_cpu(sfp->diag.rxpwr_low_alarm); 10598c2ecf20Sopenharmony_ci sfp_hwmon_to_rx_power(value); 10608c2ecf20Sopenharmony_ci return 0; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci case hwmon_power_min: 10638c2ecf20Sopenharmony_ci *value = be16_to_cpu(sfp->diag.rxpwr_low_warn); 10648c2ecf20Sopenharmony_ci sfp_hwmon_to_rx_power(value); 10658c2ecf20Sopenharmony_ci return 0; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci case hwmon_power_max: 10688c2ecf20Sopenharmony_ci *value = be16_to_cpu(sfp->diag.rxpwr_high_warn); 10698c2ecf20Sopenharmony_ci sfp_hwmon_to_rx_power(value); 10708c2ecf20Sopenharmony_ci return 0; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci case hwmon_power_crit: 10738c2ecf20Sopenharmony_ci *value = be16_to_cpu(sfp->diag.rxpwr_high_alarm); 10748c2ecf20Sopenharmony_ci sfp_hwmon_to_rx_power(value); 10758c2ecf20Sopenharmony_ci return 0; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci case hwmon_power_lcrit_alarm: 10788c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_ALARM1, &status, sizeof(status)); 10798c2ecf20Sopenharmony_ci if (err < 0) 10808c2ecf20Sopenharmony_ci return err; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci *value = !!(status & SFP_ALARM1_RXPWR_LOW); 10838c2ecf20Sopenharmony_ci return 0; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci case hwmon_power_min_alarm: 10868c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_WARN1, &status, sizeof(status)); 10878c2ecf20Sopenharmony_ci if (err < 0) 10888c2ecf20Sopenharmony_ci return err; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci *value = !!(status & SFP_WARN1_RXPWR_LOW); 10918c2ecf20Sopenharmony_ci return 0; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci case hwmon_power_max_alarm: 10948c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_WARN1, &status, sizeof(status)); 10958c2ecf20Sopenharmony_ci if (err < 0) 10968c2ecf20Sopenharmony_ci return err; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci *value = !!(status & SFP_WARN1_RXPWR_HIGH); 10998c2ecf20Sopenharmony_ci return 0; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci case hwmon_power_crit_alarm: 11028c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_ALARM1, &status, sizeof(status)); 11038c2ecf20Sopenharmony_ci if (err < 0) 11048c2ecf20Sopenharmony_ci return err; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci *value = !!(status & SFP_ALARM1_RXPWR_HIGH); 11078c2ecf20Sopenharmony_ci return 0; 11088c2ecf20Sopenharmony_ci default: 11098c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11138c2ecf20Sopenharmony_ci} 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_cistatic int sfp_hwmon_read(struct device *dev, enum hwmon_sensor_types type, 11168c2ecf20Sopenharmony_ci u32 attr, int channel, long *value) 11178c2ecf20Sopenharmony_ci{ 11188c2ecf20Sopenharmony_ci struct sfp *sfp = dev_get_drvdata(dev); 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci switch (type) { 11218c2ecf20Sopenharmony_ci case hwmon_temp: 11228c2ecf20Sopenharmony_ci return sfp_hwmon_temp(sfp, attr, value); 11238c2ecf20Sopenharmony_ci case hwmon_in: 11248c2ecf20Sopenharmony_ci return sfp_hwmon_vcc(sfp, attr, value); 11258c2ecf20Sopenharmony_ci case hwmon_curr: 11268c2ecf20Sopenharmony_ci return sfp_hwmon_bias(sfp, attr, value); 11278c2ecf20Sopenharmony_ci case hwmon_power: 11288c2ecf20Sopenharmony_ci switch (channel) { 11298c2ecf20Sopenharmony_ci case 0: 11308c2ecf20Sopenharmony_ci return sfp_hwmon_tx_power(sfp, attr, value); 11318c2ecf20Sopenharmony_ci case 1: 11328c2ecf20Sopenharmony_ci return sfp_hwmon_rx_power(sfp, attr, value); 11338c2ecf20Sopenharmony_ci default: 11348c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci default: 11378c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11388c2ecf20Sopenharmony_ci } 11398c2ecf20Sopenharmony_ci} 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_cistatic const char *const sfp_hwmon_power_labels[] = { 11428c2ecf20Sopenharmony_ci "TX_power", 11438c2ecf20Sopenharmony_ci "RX_power", 11448c2ecf20Sopenharmony_ci}; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_cistatic int sfp_hwmon_read_string(struct device *dev, 11478c2ecf20Sopenharmony_ci enum hwmon_sensor_types type, 11488c2ecf20Sopenharmony_ci u32 attr, int channel, const char **str) 11498c2ecf20Sopenharmony_ci{ 11508c2ecf20Sopenharmony_ci switch (type) { 11518c2ecf20Sopenharmony_ci case hwmon_curr: 11528c2ecf20Sopenharmony_ci switch (attr) { 11538c2ecf20Sopenharmony_ci case hwmon_curr_label: 11548c2ecf20Sopenharmony_ci *str = "bias"; 11558c2ecf20Sopenharmony_ci return 0; 11568c2ecf20Sopenharmony_ci default: 11578c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci break; 11608c2ecf20Sopenharmony_ci case hwmon_temp: 11618c2ecf20Sopenharmony_ci switch (attr) { 11628c2ecf20Sopenharmony_ci case hwmon_temp_label: 11638c2ecf20Sopenharmony_ci *str = "temperature"; 11648c2ecf20Sopenharmony_ci return 0; 11658c2ecf20Sopenharmony_ci default: 11668c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci break; 11698c2ecf20Sopenharmony_ci case hwmon_in: 11708c2ecf20Sopenharmony_ci switch (attr) { 11718c2ecf20Sopenharmony_ci case hwmon_in_label: 11728c2ecf20Sopenharmony_ci *str = "VCC"; 11738c2ecf20Sopenharmony_ci return 0; 11748c2ecf20Sopenharmony_ci default: 11758c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci break; 11788c2ecf20Sopenharmony_ci case hwmon_power: 11798c2ecf20Sopenharmony_ci switch (attr) { 11808c2ecf20Sopenharmony_ci case hwmon_power_label: 11818c2ecf20Sopenharmony_ci *str = sfp_hwmon_power_labels[channel]; 11828c2ecf20Sopenharmony_ci return 0; 11838c2ecf20Sopenharmony_ci default: 11848c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci break; 11878c2ecf20Sopenharmony_ci default: 11888c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11928c2ecf20Sopenharmony_ci} 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_cistatic const struct hwmon_ops sfp_hwmon_ops = { 11958c2ecf20Sopenharmony_ci .is_visible = sfp_hwmon_is_visible, 11968c2ecf20Sopenharmony_ci .read = sfp_hwmon_read, 11978c2ecf20Sopenharmony_ci .read_string = sfp_hwmon_read_string, 11988c2ecf20Sopenharmony_ci}; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_cistatic u32 sfp_hwmon_chip_config[] = { 12018c2ecf20Sopenharmony_ci HWMON_C_REGISTER_TZ, 12028c2ecf20Sopenharmony_ci 0, 12038c2ecf20Sopenharmony_ci}; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_cistatic const struct hwmon_channel_info sfp_hwmon_chip = { 12068c2ecf20Sopenharmony_ci .type = hwmon_chip, 12078c2ecf20Sopenharmony_ci .config = sfp_hwmon_chip_config, 12088c2ecf20Sopenharmony_ci}; 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_cistatic u32 sfp_hwmon_temp_config[] = { 12118c2ecf20Sopenharmony_ci HWMON_T_INPUT | 12128c2ecf20Sopenharmony_ci HWMON_T_MAX | HWMON_T_MIN | 12138c2ecf20Sopenharmony_ci HWMON_T_MAX_ALARM | HWMON_T_MIN_ALARM | 12148c2ecf20Sopenharmony_ci HWMON_T_CRIT | HWMON_T_LCRIT | 12158c2ecf20Sopenharmony_ci HWMON_T_CRIT_ALARM | HWMON_T_LCRIT_ALARM | 12168c2ecf20Sopenharmony_ci HWMON_T_LABEL, 12178c2ecf20Sopenharmony_ci 0, 12188c2ecf20Sopenharmony_ci}; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_cistatic const struct hwmon_channel_info sfp_hwmon_temp_channel_info = { 12218c2ecf20Sopenharmony_ci .type = hwmon_temp, 12228c2ecf20Sopenharmony_ci .config = sfp_hwmon_temp_config, 12238c2ecf20Sopenharmony_ci}; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_cistatic u32 sfp_hwmon_vcc_config[] = { 12268c2ecf20Sopenharmony_ci HWMON_I_INPUT | 12278c2ecf20Sopenharmony_ci HWMON_I_MAX | HWMON_I_MIN | 12288c2ecf20Sopenharmony_ci HWMON_I_MAX_ALARM | HWMON_I_MIN_ALARM | 12298c2ecf20Sopenharmony_ci HWMON_I_CRIT | HWMON_I_LCRIT | 12308c2ecf20Sopenharmony_ci HWMON_I_CRIT_ALARM | HWMON_I_LCRIT_ALARM | 12318c2ecf20Sopenharmony_ci HWMON_I_LABEL, 12328c2ecf20Sopenharmony_ci 0, 12338c2ecf20Sopenharmony_ci}; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_cistatic const struct hwmon_channel_info sfp_hwmon_vcc_channel_info = { 12368c2ecf20Sopenharmony_ci .type = hwmon_in, 12378c2ecf20Sopenharmony_ci .config = sfp_hwmon_vcc_config, 12388c2ecf20Sopenharmony_ci}; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_cistatic u32 sfp_hwmon_bias_config[] = { 12418c2ecf20Sopenharmony_ci HWMON_C_INPUT | 12428c2ecf20Sopenharmony_ci HWMON_C_MAX | HWMON_C_MIN | 12438c2ecf20Sopenharmony_ci HWMON_C_MAX_ALARM | HWMON_C_MIN_ALARM | 12448c2ecf20Sopenharmony_ci HWMON_C_CRIT | HWMON_C_LCRIT | 12458c2ecf20Sopenharmony_ci HWMON_C_CRIT_ALARM | HWMON_C_LCRIT_ALARM | 12468c2ecf20Sopenharmony_ci HWMON_C_LABEL, 12478c2ecf20Sopenharmony_ci 0, 12488c2ecf20Sopenharmony_ci}; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_cistatic const struct hwmon_channel_info sfp_hwmon_bias_channel_info = { 12518c2ecf20Sopenharmony_ci .type = hwmon_curr, 12528c2ecf20Sopenharmony_ci .config = sfp_hwmon_bias_config, 12538c2ecf20Sopenharmony_ci}; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_cistatic u32 sfp_hwmon_power_config[] = { 12568c2ecf20Sopenharmony_ci /* Transmit power */ 12578c2ecf20Sopenharmony_ci HWMON_P_INPUT | 12588c2ecf20Sopenharmony_ci HWMON_P_MAX | HWMON_P_MIN | 12598c2ecf20Sopenharmony_ci HWMON_P_MAX_ALARM | HWMON_P_MIN_ALARM | 12608c2ecf20Sopenharmony_ci HWMON_P_CRIT | HWMON_P_LCRIT | 12618c2ecf20Sopenharmony_ci HWMON_P_CRIT_ALARM | HWMON_P_LCRIT_ALARM | 12628c2ecf20Sopenharmony_ci HWMON_P_LABEL, 12638c2ecf20Sopenharmony_ci /* Receive power */ 12648c2ecf20Sopenharmony_ci HWMON_P_INPUT | 12658c2ecf20Sopenharmony_ci HWMON_P_MAX | HWMON_P_MIN | 12668c2ecf20Sopenharmony_ci HWMON_P_MAX_ALARM | HWMON_P_MIN_ALARM | 12678c2ecf20Sopenharmony_ci HWMON_P_CRIT | HWMON_P_LCRIT | 12688c2ecf20Sopenharmony_ci HWMON_P_CRIT_ALARM | HWMON_P_LCRIT_ALARM | 12698c2ecf20Sopenharmony_ci HWMON_P_LABEL, 12708c2ecf20Sopenharmony_ci 0, 12718c2ecf20Sopenharmony_ci}; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_cistatic const struct hwmon_channel_info sfp_hwmon_power_channel_info = { 12748c2ecf20Sopenharmony_ci .type = hwmon_power, 12758c2ecf20Sopenharmony_ci .config = sfp_hwmon_power_config, 12768c2ecf20Sopenharmony_ci}; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_cistatic const struct hwmon_channel_info *sfp_hwmon_info[] = { 12798c2ecf20Sopenharmony_ci &sfp_hwmon_chip, 12808c2ecf20Sopenharmony_ci &sfp_hwmon_vcc_channel_info, 12818c2ecf20Sopenharmony_ci &sfp_hwmon_temp_channel_info, 12828c2ecf20Sopenharmony_ci &sfp_hwmon_bias_channel_info, 12838c2ecf20Sopenharmony_ci &sfp_hwmon_power_channel_info, 12848c2ecf20Sopenharmony_ci NULL, 12858c2ecf20Sopenharmony_ci}; 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_cistatic const struct hwmon_chip_info sfp_hwmon_chip_info = { 12888c2ecf20Sopenharmony_ci .ops = &sfp_hwmon_ops, 12898c2ecf20Sopenharmony_ci .info = sfp_hwmon_info, 12908c2ecf20Sopenharmony_ci}; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_cistatic void sfp_hwmon_probe(struct work_struct *work) 12938c2ecf20Sopenharmony_ci{ 12948c2ecf20Sopenharmony_ci struct sfp *sfp = container_of(work, struct sfp, hwmon_probe.work); 12958c2ecf20Sopenharmony_ci int err, i; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci /* hwmon interface needs to access 16bit registers in atomic way to 12988c2ecf20Sopenharmony_ci * guarantee coherency of the diagnostic monitoring data. If it is not 12998c2ecf20Sopenharmony_ci * possible to guarantee coherency because EEPROM is broken in such way 13008c2ecf20Sopenharmony_ci * that does not support atomic 16bit read operation then we have to 13018c2ecf20Sopenharmony_ci * skip registration of hwmon device. 13028c2ecf20Sopenharmony_ci */ 13038c2ecf20Sopenharmony_ci if (sfp->i2c_block_size < 2) { 13048c2ecf20Sopenharmony_ci dev_info(sfp->dev, 13058c2ecf20Sopenharmony_ci "skipping hwmon device registration due to broken EEPROM\n"); 13068c2ecf20Sopenharmony_ci dev_info(sfp->dev, 13078c2ecf20Sopenharmony_ci "diagnostic EEPROM area cannot be read atomically to guarantee data coherency\n"); 13088c2ecf20Sopenharmony_ci return; 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, 0, &sfp->diag, sizeof(sfp->diag)); 13128c2ecf20Sopenharmony_ci if (err < 0) { 13138c2ecf20Sopenharmony_ci if (sfp->hwmon_tries--) { 13148c2ecf20Sopenharmony_ci mod_delayed_work(system_wq, &sfp->hwmon_probe, 13158c2ecf20Sopenharmony_ci T_PROBE_RETRY_SLOW); 13168c2ecf20Sopenharmony_ci } else { 13178c2ecf20Sopenharmony_ci dev_warn(sfp->dev, "hwmon probe failed: %d\n", err); 13188c2ecf20Sopenharmony_ci } 13198c2ecf20Sopenharmony_ci return; 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci sfp->hwmon_name = kstrdup(dev_name(sfp->dev), GFP_KERNEL); 13238c2ecf20Sopenharmony_ci if (!sfp->hwmon_name) { 13248c2ecf20Sopenharmony_ci dev_err(sfp->dev, "out of memory for hwmon name\n"); 13258c2ecf20Sopenharmony_ci return; 13268c2ecf20Sopenharmony_ci } 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci for (i = 0; sfp->hwmon_name[i]; i++) 13298c2ecf20Sopenharmony_ci if (hwmon_is_bad_char(sfp->hwmon_name[i])) 13308c2ecf20Sopenharmony_ci sfp->hwmon_name[i] = '_'; 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci sfp->hwmon_dev = hwmon_device_register_with_info(sfp->dev, 13338c2ecf20Sopenharmony_ci sfp->hwmon_name, sfp, 13348c2ecf20Sopenharmony_ci &sfp_hwmon_chip_info, 13358c2ecf20Sopenharmony_ci NULL); 13368c2ecf20Sopenharmony_ci if (IS_ERR(sfp->hwmon_dev)) 13378c2ecf20Sopenharmony_ci dev_err(sfp->dev, "failed to register hwmon device: %ld\n", 13388c2ecf20Sopenharmony_ci PTR_ERR(sfp->hwmon_dev)); 13398c2ecf20Sopenharmony_ci} 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_cistatic int sfp_hwmon_insert(struct sfp *sfp) 13428c2ecf20Sopenharmony_ci{ 13438c2ecf20Sopenharmony_ci if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE) 13448c2ecf20Sopenharmony_ci return 0; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci if (!(sfp->id.ext.diagmon & SFP_DIAGMON_DDM)) 13478c2ecf20Sopenharmony_ci return 0; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE) 13508c2ecf20Sopenharmony_ci /* This driver in general does not support address 13518c2ecf20Sopenharmony_ci * change. 13528c2ecf20Sopenharmony_ci */ 13538c2ecf20Sopenharmony_ci return 0; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci mod_delayed_work(system_wq, &sfp->hwmon_probe, 1); 13568c2ecf20Sopenharmony_ci sfp->hwmon_tries = R_PROBE_RETRY_SLOW; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci return 0; 13598c2ecf20Sopenharmony_ci} 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_cistatic void sfp_hwmon_remove(struct sfp *sfp) 13628c2ecf20Sopenharmony_ci{ 13638c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&sfp->hwmon_probe); 13648c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(sfp->hwmon_dev)) { 13658c2ecf20Sopenharmony_ci hwmon_device_unregister(sfp->hwmon_dev); 13668c2ecf20Sopenharmony_ci sfp->hwmon_dev = NULL; 13678c2ecf20Sopenharmony_ci kfree(sfp->hwmon_name); 13688c2ecf20Sopenharmony_ci } 13698c2ecf20Sopenharmony_ci} 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_cistatic int sfp_hwmon_init(struct sfp *sfp) 13728c2ecf20Sopenharmony_ci{ 13738c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&sfp->hwmon_probe, sfp_hwmon_probe); 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci return 0; 13768c2ecf20Sopenharmony_ci} 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_cistatic void sfp_hwmon_exit(struct sfp *sfp) 13798c2ecf20Sopenharmony_ci{ 13808c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&sfp->hwmon_probe); 13818c2ecf20Sopenharmony_ci} 13828c2ecf20Sopenharmony_ci#else 13838c2ecf20Sopenharmony_cistatic int sfp_hwmon_insert(struct sfp *sfp) 13848c2ecf20Sopenharmony_ci{ 13858c2ecf20Sopenharmony_ci return 0; 13868c2ecf20Sopenharmony_ci} 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_cistatic void sfp_hwmon_remove(struct sfp *sfp) 13898c2ecf20Sopenharmony_ci{ 13908c2ecf20Sopenharmony_ci} 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_cistatic int sfp_hwmon_init(struct sfp *sfp) 13938c2ecf20Sopenharmony_ci{ 13948c2ecf20Sopenharmony_ci return 0; 13958c2ecf20Sopenharmony_ci} 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_cistatic void sfp_hwmon_exit(struct sfp *sfp) 13988c2ecf20Sopenharmony_ci{ 13998c2ecf20Sopenharmony_ci} 14008c2ecf20Sopenharmony_ci#endif 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci/* Helpers */ 14038c2ecf20Sopenharmony_cistatic void sfp_module_tx_disable(struct sfp *sfp) 14048c2ecf20Sopenharmony_ci{ 14058c2ecf20Sopenharmony_ci dev_dbg(sfp->dev, "tx disable %u -> %u\n", 14068c2ecf20Sopenharmony_ci sfp->state & SFP_F_TX_DISABLE ? 1 : 0, 1); 14078c2ecf20Sopenharmony_ci sfp->state |= SFP_F_TX_DISABLE; 14088c2ecf20Sopenharmony_ci sfp_set_state(sfp, sfp->state); 14098c2ecf20Sopenharmony_ci} 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_cistatic void sfp_module_tx_enable(struct sfp *sfp) 14128c2ecf20Sopenharmony_ci{ 14138c2ecf20Sopenharmony_ci dev_dbg(sfp->dev, "tx disable %u -> %u\n", 14148c2ecf20Sopenharmony_ci sfp->state & SFP_F_TX_DISABLE ? 1 : 0, 0); 14158c2ecf20Sopenharmony_ci sfp->state &= ~SFP_F_TX_DISABLE; 14168c2ecf20Sopenharmony_ci sfp_set_state(sfp, sfp->state); 14178c2ecf20Sopenharmony_ci} 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_cistatic void sfp_module_tx_fault_reset(struct sfp *sfp) 14208c2ecf20Sopenharmony_ci{ 14218c2ecf20Sopenharmony_ci unsigned int state = sfp->state; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci if (state & SFP_F_TX_DISABLE) 14248c2ecf20Sopenharmony_ci return; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci sfp_set_state(sfp, state | SFP_F_TX_DISABLE); 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci udelay(T_RESET_US); 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci sfp_set_state(sfp, state); 14318c2ecf20Sopenharmony_ci} 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci/* SFP state machine */ 14348c2ecf20Sopenharmony_cistatic void sfp_sm_set_timer(struct sfp *sfp, unsigned int timeout) 14358c2ecf20Sopenharmony_ci{ 14368c2ecf20Sopenharmony_ci if (timeout) 14378c2ecf20Sopenharmony_ci mod_delayed_work(system_power_efficient_wq, &sfp->timeout, 14388c2ecf20Sopenharmony_ci timeout); 14398c2ecf20Sopenharmony_ci else 14408c2ecf20Sopenharmony_ci cancel_delayed_work(&sfp->timeout); 14418c2ecf20Sopenharmony_ci} 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_cistatic void sfp_sm_next(struct sfp *sfp, unsigned int state, 14448c2ecf20Sopenharmony_ci unsigned int timeout) 14458c2ecf20Sopenharmony_ci{ 14468c2ecf20Sopenharmony_ci sfp->sm_state = state; 14478c2ecf20Sopenharmony_ci sfp_sm_set_timer(sfp, timeout); 14488c2ecf20Sopenharmony_ci} 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_cistatic void sfp_sm_mod_next(struct sfp *sfp, unsigned int state, 14518c2ecf20Sopenharmony_ci unsigned int timeout) 14528c2ecf20Sopenharmony_ci{ 14538c2ecf20Sopenharmony_ci sfp->sm_mod_state = state; 14548c2ecf20Sopenharmony_ci sfp_sm_set_timer(sfp, timeout); 14558c2ecf20Sopenharmony_ci} 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_cistatic void sfp_sm_phy_detach(struct sfp *sfp) 14588c2ecf20Sopenharmony_ci{ 14598c2ecf20Sopenharmony_ci sfp_remove_phy(sfp->sfp_bus); 14608c2ecf20Sopenharmony_ci phy_device_remove(sfp->mod_phy); 14618c2ecf20Sopenharmony_ci phy_device_free(sfp->mod_phy); 14628c2ecf20Sopenharmony_ci sfp->mod_phy = NULL; 14638c2ecf20Sopenharmony_ci} 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_cistatic int sfp_sm_probe_phy(struct sfp *sfp, bool is_c45) 14668c2ecf20Sopenharmony_ci{ 14678c2ecf20Sopenharmony_ci struct phy_device *phy; 14688c2ecf20Sopenharmony_ci int err; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci phy = get_phy_device(sfp->i2c_mii, SFP_PHY_ADDR, is_c45); 14718c2ecf20Sopenharmony_ci if (phy == ERR_PTR(-ENODEV)) 14728c2ecf20Sopenharmony_ci return PTR_ERR(phy); 14738c2ecf20Sopenharmony_ci if (IS_ERR(phy)) { 14748c2ecf20Sopenharmony_ci dev_err(sfp->dev, "mdiobus scan returned %ld\n", PTR_ERR(phy)); 14758c2ecf20Sopenharmony_ci return PTR_ERR(phy); 14768c2ecf20Sopenharmony_ci } 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci err = phy_device_register(phy); 14798c2ecf20Sopenharmony_ci if (err) { 14808c2ecf20Sopenharmony_ci phy_device_free(phy); 14818c2ecf20Sopenharmony_ci dev_err(sfp->dev, "phy_device_register failed: %d\n", err); 14828c2ecf20Sopenharmony_ci return err; 14838c2ecf20Sopenharmony_ci } 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci err = sfp_add_phy(sfp->sfp_bus, phy); 14868c2ecf20Sopenharmony_ci if (err) { 14878c2ecf20Sopenharmony_ci phy_device_remove(phy); 14888c2ecf20Sopenharmony_ci phy_device_free(phy); 14898c2ecf20Sopenharmony_ci dev_err(sfp->dev, "sfp_add_phy failed: %d\n", err); 14908c2ecf20Sopenharmony_ci return err; 14918c2ecf20Sopenharmony_ci } 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci sfp->mod_phy = phy; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci return 0; 14968c2ecf20Sopenharmony_ci} 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_cistatic void sfp_sm_link_up(struct sfp *sfp) 14998c2ecf20Sopenharmony_ci{ 15008c2ecf20Sopenharmony_ci sfp_link_up(sfp->sfp_bus); 15018c2ecf20Sopenharmony_ci sfp_sm_next(sfp, SFP_S_LINK_UP, 0); 15028c2ecf20Sopenharmony_ci} 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_cistatic void sfp_sm_link_down(struct sfp *sfp) 15058c2ecf20Sopenharmony_ci{ 15068c2ecf20Sopenharmony_ci sfp_link_down(sfp->sfp_bus); 15078c2ecf20Sopenharmony_ci} 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_cistatic void sfp_sm_link_check_los(struct sfp *sfp) 15108c2ecf20Sopenharmony_ci{ 15118c2ecf20Sopenharmony_ci const __be16 los_inverted = cpu_to_be16(SFP_OPTIONS_LOS_INVERTED); 15128c2ecf20Sopenharmony_ci const __be16 los_normal = cpu_to_be16(SFP_OPTIONS_LOS_NORMAL); 15138c2ecf20Sopenharmony_ci __be16 los_options = sfp->id.ext.options & (los_inverted | los_normal); 15148c2ecf20Sopenharmony_ci bool los = false; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci /* If neither SFP_OPTIONS_LOS_INVERTED nor SFP_OPTIONS_LOS_NORMAL 15178c2ecf20Sopenharmony_ci * are set, we assume that no LOS signal is available. If both are 15188c2ecf20Sopenharmony_ci * set, we assume LOS is not implemented (and is meaningless.) 15198c2ecf20Sopenharmony_ci */ 15208c2ecf20Sopenharmony_ci if (los_options == los_inverted) 15218c2ecf20Sopenharmony_ci los = !(sfp->state & SFP_F_LOS); 15228c2ecf20Sopenharmony_ci else if (los_options == los_normal) 15238c2ecf20Sopenharmony_ci los = !!(sfp->state & SFP_F_LOS); 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci if (los) 15268c2ecf20Sopenharmony_ci sfp_sm_next(sfp, SFP_S_WAIT_LOS, 0); 15278c2ecf20Sopenharmony_ci else 15288c2ecf20Sopenharmony_ci sfp_sm_link_up(sfp); 15298c2ecf20Sopenharmony_ci} 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_cistatic bool sfp_los_event_active(struct sfp *sfp, unsigned int event) 15328c2ecf20Sopenharmony_ci{ 15338c2ecf20Sopenharmony_ci const __be16 los_inverted = cpu_to_be16(SFP_OPTIONS_LOS_INVERTED); 15348c2ecf20Sopenharmony_ci const __be16 los_normal = cpu_to_be16(SFP_OPTIONS_LOS_NORMAL); 15358c2ecf20Sopenharmony_ci __be16 los_options = sfp->id.ext.options & (los_inverted | los_normal); 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci return (los_options == los_inverted && event == SFP_E_LOS_LOW) || 15388c2ecf20Sopenharmony_ci (los_options == los_normal && event == SFP_E_LOS_HIGH); 15398c2ecf20Sopenharmony_ci} 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_cistatic bool sfp_los_event_inactive(struct sfp *sfp, unsigned int event) 15428c2ecf20Sopenharmony_ci{ 15438c2ecf20Sopenharmony_ci const __be16 los_inverted = cpu_to_be16(SFP_OPTIONS_LOS_INVERTED); 15448c2ecf20Sopenharmony_ci const __be16 los_normal = cpu_to_be16(SFP_OPTIONS_LOS_NORMAL); 15458c2ecf20Sopenharmony_ci __be16 los_options = sfp->id.ext.options & (los_inverted | los_normal); 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci return (los_options == los_inverted && event == SFP_E_LOS_HIGH) || 15488c2ecf20Sopenharmony_ci (los_options == los_normal && event == SFP_E_LOS_LOW); 15498c2ecf20Sopenharmony_ci} 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_cistatic void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn) 15528c2ecf20Sopenharmony_ci{ 15538c2ecf20Sopenharmony_ci if (sfp->sm_fault_retries && !--sfp->sm_fault_retries) { 15548c2ecf20Sopenharmony_ci dev_err(sfp->dev, 15558c2ecf20Sopenharmony_ci "module persistently indicates fault, disabling\n"); 15568c2ecf20Sopenharmony_ci sfp_sm_next(sfp, SFP_S_TX_DISABLE, 0); 15578c2ecf20Sopenharmony_ci } else { 15588c2ecf20Sopenharmony_ci if (warn) 15598c2ecf20Sopenharmony_ci dev_err(sfp->dev, "module transmit fault indicated\n"); 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci sfp_sm_next(sfp, next_state, T_FAULT_RECOVER); 15628c2ecf20Sopenharmony_ci } 15638c2ecf20Sopenharmony_ci} 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci/* Probe a SFP for a PHY device if the module supports copper - the PHY 15668c2ecf20Sopenharmony_ci * normally sits at I2C bus address 0x56, and may either be a clause 22 15678c2ecf20Sopenharmony_ci * or clause 45 PHY. 15688c2ecf20Sopenharmony_ci * 15698c2ecf20Sopenharmony_ci * Clause 22 copper SFP modules normally operate in Cisco SGMII mode with 15708c2ecf20Sopenharmony_ci * negotiation enabled, but some may be in 1000base-X - which is for the 15718c2ecf20Sopenharmony_ci * PHY driver to determine. 15728c2ecf20Sopenharmony_ci * 15738c2ecf20Sopenharmony_ci * Clause 45 copper SFP+ modules (10G) appear to switch their interface 15748c2ecf20Sopenharmony_ci * mode according to the negotiated line speed. 15758c2ecf20Sopenharmony_ci */ 15768c2ecf20Sopenharmony_cistatic int sfp_sm_probe_for_phy(struct sfp *sfp) 15778c2ecf20Sopenharmony_ci{ 15788c2ecf20Sopenharmony_ci int err = 0; 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci switch (sfp->id.base.extended_cc) { 15818c2ecf20Sopenharmony_ci case SFF8024_ECC_10GBASE_T_SFI: 15828c2ecf20Sopenharmony_ci case SFF8024_ECC_10GBASE_T_SR: 15838c2ecf20Sopenharmony_ci case SFF8024_ECC_5GBASE_T: 15848c2ecf20Sopenharmony_ci case SFF8024_ECC_2_5GBASE_T: 15858c2ecf20Sopenharmony_ci err = sfp_sm_probe_phy(sfp, true); 15868c2ecf20Sopenharmony_ci break; 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci default: 15898c2ecf20Sopenharmony_ci if (sfp->id.base.e1000_base_t) 15908c2ecf20Sopenharmony_ci err = sfp_sm_probe_phy(sfp, false); 15918c2ecf20Sopenharmony_ci break; 15928c2ecf20Sopenharmony_ci } 15938c2ecf20Sopenharmony_ci return err; 15948c2ecf20Sopenharmony_ci} 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_cistatic int sfp_module_parse_power(struct sfp *sfp) 15978c2ecf20Sopenharmony_ci{ 15988c2ecf20Sopenharmony_ci u32 power_mW = 1000; 15998c2ecf20Sopenharmony_ci bool supports_a2; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_POWER_DECL)) 16028c2ecf20Sopenharmony_ci power_mW = 1500; 16038c2ecf20Sopenharmony_ci if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL)) 16048c2ecf20Sopenharmony_ci power_mW = 2000; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci supports_a2 = sfp->id.ext.sff8472_compliance != 16078c2ecf20Sopenharmony_ci SFP_SFF8472_COMPLIANCE_NONE || 16088c2ecf20Sopenharmony_ci sfp->id.ext.diagmon & SFP_DIAGMON_DDM; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci if (power_mW > sfp->max_power_mW) { 16118c2ecf20Sopenharmony_ci /* Module power specification exceeds the allowed maximum. */ 16128c2ecf20Sopenharmony_ci if (!supports_a2) { 16138c2ecf20Sopenharmony_ci /* The module appears not to implement bus address 16148c2ecf20Sopenharmony_ci * 0xa2, so assume that the module powers up in the 16158c2ecf20Sopenharmony_ci * indicated mode. 16168c2ecf20Sopenharmony_ci */ 16178c2ecf20Sopenharmony_ci dev_err(sfp->dev, 16188c2ecf20Sopenharmony_ci "Host does not support %u.%uW modules\n", 16198c2ecf20Sopenharmony_ci power_mW / 1000, (power_mW / 100) % 10); 16208c2ecf20Sopenharmony_ci return -EINVAL; 16218c2ecf20Sopenharmony_ci } else { 16228c2ecf20Sopenharmony_ci dev_warn(sfp->dev, 16238c2ecf20Sopenharmony_ci "Host does not support %u.%uW modules, module left in power mode 1\n", 16248c2ecf20Sopenharmony_ci power_mW / 1000, (power_mW / 100) % 10); 16258c2ecf20Sopenharmony_ci return 0; 16268c2ecf20Sopenharmony_ci } 16278c2ecf20Sopenharmony_ci } 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci if (power_mW <= 1000) { 16308c2ecf20Sopenharmony_ci /* Modules below 1W do not require a power change sequence */ 16318c2ecf20Sopenharmony_ci sfp->module_power_mW = power_mW; 16328c2ecf20Sopenharmony_ci return 0; 16338c2ecf20Sopenharmony_ci } 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci if (!supports_a2) { 16368c2ecf20Sopenharmony_ci /* The module power level is below the host maximum and the 16378c2ecf20Sopenharmony_ci * module appears not to implement bus address 0xa2, so assume 16388c2ecf20Sopenharmony_ci * that the module powers up in the indicated mode. 16398c2ecf20Sopenharmony_ci */ 16408c2ecf20Sopenharmony_ci return 0; 16418c2ecf20Sopenharmony_ci } 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci /* If the module requires a higher power mode, but also requires 16448c2ecf20Sopenharmony_ci * an address change sequence, warn the user that the module may 16458c2ecf20Sopenharmony_ci * not be functional. 16468c2ecf20Sopenharmony_ci */ 16478c2ecf20Sopenharmony_ci if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE) { 16488c2ecf20Sopenharmony_ci dev_warn(sfp->dev, 16498c2ecf20Sopenharmony_ci "Address Change Sequence not supported but module requires %u.%uW, module may not be functional\n", 16508c2ecf20Sopenharmony_ci power_mW / 1000, (power_mW / 100) % 10); 16518c2ecf20Sopenharmony_ci return 0; 16528c2ecf20Sopenharmony_ci } 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci sfp->module_power_mW = power_mW; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci return 0; 16578c2ecf20Sopenharmony_ci} 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_cistatic int sfp_sm_mod_hpower(struct sfp *sfp, bool enable) 16608c2ecf20Sopenharmony_ci{ 16618c2ecf20Sopenharmony_ci u8 val; 16628c2ecf20Sopenharmony_ci int err; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci err = sfp_read(sfp, true, SFP_EXT_STATUS, &val, sizeof(val)); 16658c2ecf20Sopenharmony_ci if (err != sizeof(val)) { 16668c2ecf20Sopenharmony_ci dev_err(sfp->dev, "Failed to read EEPROM: %d\n", err); 16678c2ecf20Sopenharmony_ci return -EAGAIN; 16688c2ecf20Sopenharmony_ci } 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci /* DM7052 reports as a high power module, responds to reads (with 16718c2ecf20Sopenharmony_ci * all bytes 0xff) at 0x51 but does not accept writes. In any case, 16728c2ecf20Sopenharmony_ci * if the bit is already set, we're already in high power mode. 16738c2ecf20Sopenharmony_ci */ 16748c2ecf20Sopenharmony_ci if (!!(val & BIT(0)) == enable) 16758c2ecf20Sopenharmony_ci return 0; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci if (enable) 16788c2ecf20Sopenharmony_ci val |= BIT(0); 16798c2ecf20Sopenharmony_ci else 16808c2ecf20Sopenharmony_ci val &= ~BIT(0); 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci err = sfp_write(sfp, true, SFP_EXT_STATUS, &val, sizeof(val)); 16838c2ecf20Sopenharmony_ci if (err != sizeof(val)) { 16848c2ecf20Sopenharmony_ci dev_err(sfp->dev, "Failed to write EEPROM: %d\n", err); 16858c2ecf20Sopenharmony_ci return -EAGAIN; 16868c2ecf20Sopenharmony_ci } 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci if (enable) 16898c2ecf20Sopenharmony_ci dev_info(sfp->dev, "Module switched to %u.%uW power level\n", 16908c2ecf20Sopenharmony_ci sfp->module_power_mW / 1000, 16918c2ecf20Sopenharmony_ci (sfp->module_power_mW / 100) % 10); 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci return 0; 16948c2ecf20Sopenharmony_ci} 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci/* GPON modules based on Realtek RTL8672 and RTL9601C chips (e.g. V-SOL 16978c2ecf20Sopenharmony_ci * V2801F, CarlitoxxPro CPGOS03-0490, Ubiquiti U-Fiber Instant, ...) do 16988c2ecf20Sopenharmony_ci * not support multibyte reads from the EEPROM. Each multi-byte read 16998c2ecf20Sopenharmony_ci * operation returns just one byte of EEPROM followed by zeros. There is 17008c2ecf20Sopenharmony_ci * no way to identify which modules are using Realtek RTL8672 and RTL9601C 17018c2ecf20Sopenharmony_ci * chips. Moreover every OEM of V-SOL V2801F module puts its own vendor 17028c2ecf20Sopenharmony_ci * name and vendor id into EEPROM, so there is even no way to detect if 17038c2ecf20Sopenharmony_ci * module is V-SOL V2801F. Therefore check for those zeros in the read 17048c2ecf20Sopenharmony_ci * data and then based on check switch to reading EEPROM to one byte 17058c2ecf20Sopenharmony_ci * at a time. 17068c2ecf20Sopenharmony_ci */ 17078c2ecf20Sopenharmony_cistatic bool sfp_id_needs_byte_io(struct sfp *sfp, void *buf, size_t len) 17088c2ecf20Sopenharmony_ci{ 17098c2ecf20Sopenharmony_ci size_t i, block_size = sfp->i2c_block_size; 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci /* Already using byte IO */ 17128c2ecf20Sopenharmony_ci if (block_size == 1) 17138c2ecf20Sopenharmony_ci return false; 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci for (i = 1; i < len; i += block_size) { 17168c2ecf20Sopenharmony_ci if (memchr_inv(buf + i, '\0', min(block_size - 1, len - i))) 17178c2ecf20Sopenharmony_ci return false; 17188c2ecf20Sopenharmony_ci } 17198c2ecf20Sopenharmony_ci return true; 17208c2ecf20Sopenharmony_ci} 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_cistatic int sfp_cotsworks_fixup_check(struct sfp *sfp, struct sfp_eeprom_id *id) 17238c2ecf20Sopenharmony_ci{ 17248c2ecf20Sopenharmony_ci u8 check; 17258c2ecf20Sopenharmony_ci int err; 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci if (id->base.phys_id != SFF8024_ID_SFF_8472 || 17288c2ecf20Sopenharmony_ci id->base.phys_ext_id != SFP_PHYS_EXT_ID_SFP || 17298c2ecf20Sopenharmony_ci id->base.connector != SFF8024_CONNECTOR_LC) { 17308c2ecf20Sopenharmony_ci dev_warn(sfp->dev, "Rewriting fiber module EEPROM with corrected values\n"); 17318c2ecf20Sopenharmony_ci id->base.phys_id = SFF8024_ID_SFF_8472; 17328c2ecf20Sopenharmony_ci id->base.phys_ext_id = SFP_PHYS_EXT_ID_SFP; 17338c2ecf20Sopenharmony_ci id->base.connector = SFF8024_CONNECTOR_LC; 17348c2ecf20Sopenharmony_ci err = sfp_write(sfp, false, SFP_PHYS_ID, &id->base, 3); 17358c2ecf20Sopenharmony_ci if (err != 3) { 17368c2ecf20Sopenharmony_ci dev_err(sfp->dev, "Failed to rewrite module EEPROM: %d\n", err); 17378c2ecf20Sopenharmony_ci return err; 17388c2ecf20Sopenharmony_ci } 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci /* Cotsworks modules have been found to require a delay between write operations. */ 17418c2ecf20Sopenharmony_ci mdelay(50); 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci /* Update base structure checksum */ 17448c2ecf20Sopenharmony_ci check = sfp_check(&id->base, sizeof(id->base) - 1); 17458c2ecf20Sopenharmony_ci err = sfp_write(sfp, false, SFP_CC_BASE, &check, 1); 17468c2ecf20Sopenharmony_ci if (err != 1) { 17478c2ecf20Sopenharmony_ci dev_err(sfp->dev, "Failed to update base structure checksum in fiber module EEPROM: %d\n", err); 17488c2ecf20Sopenharmony_ci return err; 17498c2ecf20Sopenharmony_ci } 17508c2ecf20Sopenharmony_ci } 17518c2ecf20Sopenharmony_ci return 0; 17528c2ecf20Sopenharmony_ci} 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_cistatic int sfp_sm_mod_probe(struct sfp *sfp, bool report) 17558c2ecf20Sopenharmony_ci{ 17568c2ecf20Sopenharmony_ci /* SFP module inserted - read I2C data */ 17578c2ecf20Sopenharmony_ci struct sfp_eeprom_id id; 17588c2ecf20Sopenharmony_ci bool cotsworks_sfbg; 17598c2ecf20Sopenharmony_ci bool cotsworks; 17608c2ecf20Sopenharmony_ci u8 check; 17618c2ecf20Sopenharmony_ci int ret; 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci sfp->i2c_block_size = SFP_EEPROM_BLOCK_SIZE; 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci ret = sfp_read(sfp, false, 0, &id.base, sizeof(id.base)); 17668c2ecf20Sopenharmony_ci if (ret < 0) { 17678c2ecf20Sopenharmony_ci if (report) 17688c2ecf20Sopenharmony_ci dev_err(sfp->dev, "failed to read EEPROM: %d\n", ret); 17698c2ecf20Sopenharmony_ci return -EAGAIN; 17708c2ecf20Sopenharmony_ci } 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci if (ret != sizeof(id.base)) { 17738c2ecf20Sopenharmony_ci dev_err(sfp->dev, "EEPROM short read: %d\n", ret); 17748c2ecf20Sopenharmony_ci return -EAGAIN; 17758c2ecf20Sopenharmony_ci } 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci /* Some SFP modules (e.g. Nokia 3FE46541AA) lock up if read from 17788c2ecf20Sopenharmony_ci * address 0x51 is just one byte at a time. Also SFF-8472 requires 17798c2ecf20Sopenharmony_ci * that EEPROM supports atomic 16bit read operation for diagnostic 17808c2ecf20Sopenharmony_ci * fields, so do not switch to one byte reading at a time unless it 17818c2ecf20Sopenharmony_ci * is really required and we have no other option. 17828c2ecf20Sopenharmony_ci */ 17838c2ecf20Sopenharmony_ci if (sfp_id_needs_byte_io(sfp, &id.base, sizeof(id.base))) { 17848c2ecf20Sopenharmony_ci dev_info(sfp->dev, 17858c2ecf20Sopenharmony_ci "Detected broken RTL8672/RTL9601C emulated EEPROM\n"); 17868c2ecf20Sopenharmony_ci dev_info(sfp->dev, 17878c2ecf20Sopenharmony_ci "Switching to reading EEPROM to one byte at a time\n"); 17888c2ecf20Sopenharmony_ci sfp->i2c_block_size = 1; 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci ret = sfp_read(sfp, false, 0, &id.base, sizeof(id.base)); 17918c2ecf20Sopenharmony_ci if (ret < 0) { 17928c2ecf20Sopenharmony_ci if (report) 17938c2ecf20Sopenharmony_ci dev_err(sfp->dev, "failed to read EEPROM: %d\n", 17948c2ecf20Sopenharmony_ci ret); 17958c2ecf20Sopenharmony_ci return -EAGAIN; 17968c2ecf20Sopenharmony_ci } 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci if (ret != sizeof(id.base)) { 17998c2ecf20Sopenharmony_ci dev_err(sfp->dev, "EEPROM short read: %d\n", ret); 18008c2ecf20Sopenharmony_ci return -EAGAIN; 18018c2ecf20Sopenharmony_ci } 18028c2ecf20Sopenharmony_ci } 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci /* Cotsworks do not seem to update the checksums when they 18058c2ecf20Sopenharmony_ci * do the final programming with the final module part number, 18068c2ecf20Sopenharmony_ci * serial number and date code. 18078c2ecf20Sopenharmony_ci */ 18088c2ecf20Sopenharmony_ci cotsworks = !memcmp(id.base.vendor_name, "COTSWORKS ", 16); 18098c2ecf20Sopenharmony_ci cotsworks_sfbg = !memcmp(id.base.vendor_pn, "SFBG", 4); 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci /* Cotsworks SFF module EEPROM do not always have valid phys_id, 18128c2ecf20Sopenharmony_ci * phys_ext_id, and connector bytes. Rewrite SFF EEPROM bytes if 18138c2ecf20Sopenharmony_ci * Cotsworks PN matches and bytes are not correct. 18148c2ecf20Sopenharmony_ci */ 18158c2ecf20Sopenharmony_ci if (cotsworks && cotsworks_sfbg) { 18168c2ecf20Sopenharmony_ci ret = sfp_cotsworks_fixup_check(sfp, &id); 18178c2ecf20Sopenharmony_ci if (ret < 0) 18188c2ecf20Sopenharmony_ci return ret; 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci /* Validate the checksum over the base structure */ 18228c2ecf20Sopenharmony_ci check = sfp_check(&id.base, sizeof(id.base) - 1); 18238c2ecf20Sopenharmony_ci if (check != id.base.cc_base) { 18248c2ecf20Sopenharmony_ci if (cotsworks) { 18258c2ecf20Sopenharmony_ci dev_warn(sfp->dev, 18268c2ecf20Sopenharmony_ci "EEPROM base structure checksum failure (0x%02x != 0x%02x)\n", 18278c2ecf20Sopenharmony_ci check, id.base.cc_base); 18288c2ecf20Sopenharmony_ci } else { 18298c2ecf20Sopenharmony_ci dev_err(sfp->dev, 18308c2ecf20Sopenharmony_ci "EEPROM base structure checksum failure: 0x%02x != 0x%02x\n", 18318c2ecf20Sopenharmony_ci check, id.base.cc_base); 18328c2ecf20Sopenharmony_ci print_hex_dump(KERN_ERR, "sfp EE: ", DUMP_PREFIX_OFFSET, 18338c2ecf20Sopenharmony_ci 16, 1, &id, sizeof(id), true); 18348c2ecf20Sopenharmony_ci return -EINVAL; 18358c2ecf20Sopenharmony_ci } 18368c2ecf20Sopenharmony_ci } 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci ret = sfp_read(sfp, false, SFP_CC_BASE + 1, &id.ext, sizeof(id.ext)); 18398c2ecf20Sopenharmony_ci if (ret < 0) { 18408c2ecf20Sopenharmony_ci if (report) 18418c2ecf20Sopenharmony_ci dev_err(sfp->dev, "failed to read EEPROM: %d\n", ret); 18428c2ecf20Sopenharmony_ci return -EAGAIN; 18438c2ecf20Sopenharmony_ci } 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci if (ret != sizeof(id.ext)) { 18468c2ecf20Sopenharmony_ci dev_err(sfp->dev, "EEPROM short read: %d\n", ret); 18478c2ecf20Sopenharmony_ci return -EAGAIN; 18488c2ecf20Sopenharmony_ci } 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci check = sfp_check(&id.ext, sizeof(id.ext) - 1); 18518c2ecf20Sopenharmony_ci if (check != id.ext.cc_ext) { 18528c2ecf20Sopenharmony_ci if (cotsworks) { 18538c2ecf20Sopenharmony_ci dev_warn(sfp->dev, 18548c2ecf20Sopenharmony_ci "EEPROM extended structure checksum failure (0x%02x != 0x%02x)\n", 18558c2ecf20Sopenharmony_ci check, id.ext.cc_ext); 18568c2ecf20Sopenharmony_ci } else { 18578c2ecf20Sopenharmony_ci dev_err(sfp->dev, 18588c2ecf20Sopenharmony_ci "EEPROM extended structure checksum failure: 0x%02x != 0x%02x\n", 18598c2ecf20Sopenharmony_ci check, id.ext.cc_ext); 18608c2ecf20Sopenharmony_ci print_hex_dump(KERN_ERR, "sfp EE: ", DUMP_PREFIX_OFFSET, 18618c2ecf20Sopenharmony_ci 16, 1, &id, sizeof(id), true); 18628c2ecf20Sopenharmony_ci memset(&id.ext, 0, sizeof(id.ext)); 18638c2ecf20Sopenharmony_ci } 18648c2ecf20Sopenharmony_ci } 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci sfp->id = id; 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci dev_info(sfp->dev, "module %.*s %.*s rev %.*s sn %.*s dc %.*s\n", 18698c2ecf20Sopenharmony_ci (int)sizeof(id.base.vendor_name), id.base.vendor_name, 18708c2ecf20Sopenharmony_ci (int)sizeof(id.base.vendor_pn), id.base.vendor_pn, 18718c2ecf20Sopenharmony_ci (int)sizeof(id.base.vendor_rev), id.base.vendor_rev, 18728c2ecf20Sopenharmony_ci (int)sizeof(id.ext.vendor_sn), id.ext.vendor_sn, 18738c2ecf20Sopenharmony_ci (int)sizeof(id.ext.datecode), id.ext.datecode); 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci /* Check whether we support this module */ 18768c2ecf20Sopenharmony_ci if (!sfp->type->module_supported(&id)) { 18778c2ecf20Sopenharmony_ci dev_err(sfp->dev, 18788c2ecf20Sopenharmony_ci "module is not supported - phys id 0x%02x 0x%02x\n", 18798c2ecf20Sopenharmony_ci sfp->id.base.phys_id, sfp->id.base.phys_ext_id); 18808c2ecf20Sopenharmony_ci return -EINVAL; 18818c2ecf20Sopenharmony_ci } 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci /* If the module requires address swap mode, warn about it */ 18848c2ecf20Sopenharmony_ci if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE) 18858c2ecf20Sopenharmony_ci dev_warn(sfp->dev, 18868c2ecf20Sopenharmony_ci "module address swap to access page 0xA2 is not supported.\n"); 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci /* Parse the module power requirement */ 18898c2ecf20Sopenharmony_ci ret = sfp_module_parse_power(sfp); 18908c2ecf20Sopenharmony_ci if (ret < 0) 18918c2ecf20Sopenharmony_ci return ret; 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci if (!memcmp(id.base.vendor_name, "ALCATELLUCENT ", 16) && 18948c2ecf20Sopenharmony_ci !memcmp(id.base.vendor_pn, "3FE46541AA ", 16)) 18958c2ecf20Sopenharmony_ci sfp->module_t_start_up = T_START_UP_BAD_GPON; 18968c2ecf20Sopenharmony_ci else 18978c2ecf20Sopenharmony_ci sfp->module_t_start_up = T_START_UP; 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci if (!memcmp(id.base.vendor_name, "HUAWEI ", 16) && 19008c2ecf20Sopenharmony_ci !memcmp(id.base.vendor_pn, "MA5671A ", 16)) 19018c2ecf20Sopenharmony_ci sfp->tx_fault_ignore = true; 19028c2ecf20Sopenharmony_ci else 19038c2ecf20Sopenharmony_ci sfp->tx_fault_ignore = false; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci return 0; 19068c2ecf20Sopenharmony_ci} 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_cistatic void sfp_sm_mod_remove(struct sfp *sfp) 19098c2ecf20Sopenharmony_ci{ 19108c2ecf20Sopenharmony_ci if (sfp->sm_mod_state > SFP_MOD_WAITDEV) 19118c2ecf20Sopenharmony_ci sfp_module_remove(sfp->sfp_bus); 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci sfp_hwmon_remove(sfp); 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci memset(&sfp->id, 0, sizeof(sfp->id)); 19168c2ecf20Sopenharmony_ci sfp->module_power_mW = 0; 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_ci dev_info(sfp->dev, "module removed\n"); 19198c2ecf20Sopenharmony_ci} 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci/* This state machine tracks the upstream's state */ 19228c2ecf20Sopenharmony_cistatic void sfp_sm_device(struct sfp *sfp, unsigned int event) 19238c2ecf20Sopenharmony_ci{ 19248c2ecf20Sopenharmony_ci switch (sfp->sm_dev_state) { 19258c2ecf20Sopenharmony_ci default: 19268c2ecf20Sopenharmony_ci if (event == SFP_E_DEV_ATTACH) 19278c2ecf20Sopenharmony_ci sfp->sm_dev_state = SFP_DEV_DOWN; 19288c2ecf20Sopenharmony_ci break; 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci case SFP_DEV_DOWN: 19318c2ecf20Sopenharmony_ci if (event == SFP_E_DEV_DETACH) 19328c2ecf20Sopenharmony_ci sfp->sm_dev_state = SFP_DEV_DETACHED; 19338c2ecf20Sopenharmony_ci else if (event == SFP_E_DEV_UP) 19348c2ecf20Sopenharmony_ci sfp->sm_dev_state = SFP_DEV_UP; 19358c2ecf20Sopenharmony_ci break; 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci case SFP_DEV_UP: 19388c2ecf20Sopenharmony_ci if (event == SFP_E_DEV_DETACH) 19398c2ecf20Sopenharmony_ci sfp->sm_dev_state = SFP_DEV_DETACHED; 19408c2ecf20Sopenharmony_ci else if (event == SFP_E_DEV_DOWN) 19418c2ecf20Sopenharmony_ci sfp->sm_dev_state = SFP_DEV_DOWN; 19428c2ecf20Sopenharmony_ci break; 19438c2ecf20Sopenharmony_ci } 19448c2ecf20Sopenharmony_ci} 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci/* This state machine tracks the insert/remove state of the module, probes 19478c2ecf20Sopenharmony_ci * the on-board EEPROM, and sets up the power level. 19488c2ecf20Sopenharmony_ci */ 19498c2ecf20Sopenharmony_cistatic void sfp_sm_module(struct sfp *sfp, unsigned int event) 19508c2ecf20Sopenharmony_ci{ 19518c2ecf20Sopenharmony_ci int err; 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci /* Handle remove event globally, it resets this state machine */ 19548c2ecf20Sopenharmony_ci if (event == SFP_E_REMOVE) { 19558c2ecf20Sopenharmony_ci if (sfp->sm_mod_state > SFP_MOD_PROBE) 19568c2ecf20Sopenharmony_ci sfp_sm_mod_remove(sfp); 19578c2ecf20Sopenharmony_ci sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0); 19588c2ecf20Sopenharmony_ci return; 19598c2ecf20Sopenharmony_ci } 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci /* Handle device detach globally */ 19628c2ecf20Sopenharmony_ci if (sfp->sm_dev_state < SFP_DEV_DOWN && 19638c2ecf20Sopenharmony_ci sfp->sm_mod_state > SFP_MOD_WAITDEV) { 19648c2ecf20Sopenharmony_ci if (sfp->module_power_mW > 1000 && 19658c2ecf20Sopenharmony_ci sfp->sm_mod_state > SFP_MOD_HPOWER) 19668c2ecf20Sopenharmony_ci sfp_sm_mod_hpower(sfp, false); 19678c2ecf20Sopenharmony_ci sfp_sm_mod_next(sfp, SFP_MOD_WAITDEV, 0); 19688c2ecf20Sopenharmony_ci return; 19698c2ecf20Sopenharmony_ci } 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci switch (sfp->sm_mod_state) { 19728c2ecf20Sopenharmony_ci default: 19738c2ecf20Sopenharmony_ci if (event == SFP_E_INSERT) { 19748c2ecf20Sopenharmony_ci sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL); 19758c2ecf20Sopenharmony_ci sfp->sm_mod_tries_init = R_PROBE_RETRY_INIT; 19768c2ecf20Sopenharmony_ci sfp->sm_mod_tries = R_PROBE_RETRY_SLOW; 19778c2ecf20Sopenharmony_ci } 19788c2ecf20Sopenharmony_ci break; 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci case SFP_MOD_PROBE: 19818c2ecf20Sopenharmony_ci /* Wait for T_PROBE_INIT to time out */ 19828c2ecf20Sopenharmony_ci if (event != SFP_E_TIMEOUT) 19838c2ecf20Sopenharmony_ci break; 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci err = sfp_sm_mod_probe(sfp, sfp->sm_mod_tries == 1); 19868c2ecf20Sopenharmony_ci if (err == -EAGAIN) { 19878c2ecf20Sopenharmony_ci if (sfp->sm_mod_tries_init && 19888c2ecf20Sopenharmony_ci --sfp->sm_mod_tries_init) { 19898c2ecf20Sopenharmony_ci sfp_sm_set_timer(sfp, T_PROBE_RETRY_INIT); 19908c2ecf20Sopenharmony_ci break; 19918c2ecf20Sopenharmony_ci } else if (sfp->sm_mod_tries && --sfp->sm_mod_tries) { 19928c2ecf20Sopenharmony_ci if (sfp->sm_mod_tries == R_PROBE_RETRY_SLOW - 1) 19938c2ecf20Sopenharmony_ci dev_warn(sfp->dev, 19948c2ecf20Sopenharmony_ci "please wait, module slow to respond\n"); 19958c2ecf20Sopenharmony_ci sfp_sm_set_timer(sfp, T_PROBE_RETRY_SLOW); 19968c2ecf20Sopenharmony_ci break; 19978c2ecf20Sopenharmony_ci } 19988c2ecf20Sopenharmony_ci } 19998c2ecf20Sopenharmony_ci if (err < 0) { 20008c2ecf20Sopenharmony_ci sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); 20018c2ecf20Sopenharmony_ci break; 20028c2ecf20Sopenharmony_ci } 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci err = sfp_hwmon_insert(sfp); 20058c2ecf20Sopenharmony_ci if (err) 20068c2ecf20Sopenharmony_ci dev_warn(sfp->dev, "hwmon probe failed: %d\n", err); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci sfp_sm_mod_next(sfp, SFP_MOD_WAITDEV, 0); 20098c2ecf20Sopenharmony_ci fallthrough; 20108c2ecf20Sopenharmony_ci case SFP_MOD_WAITDEV: 20118c2ecf20Sopenharmony_ci /* Ensure that the device is attached before proceeding */ 20128c2ecf20Sopenharmony_ci if (sfp->sm_dev_state < SFP_DEV_DOWN) 20138c2ecf20Sopenharmony_ci break; 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci /* Report the module insertion to the upstream device */ 20168c2ecf20Sopenharmony_ci err = sfp_module_insert(sfp->sfp_bus, &sfp->id); 20178c2ecf20Sopenharmony_ci if (err < 0) { 20188c2ecf20Sopenharmony_ci sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); 20198c2ecf20Sopenharmony_ci break; 20208c2ecf20Sopenharmony_ci } 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci /* If this is a power level 1 module, we are done */ 20238c2ecf20Sopenharmony_ci if (sfp->module_power_mW <= 1000) 20248c2ecf20Sopenharmony_ci goto insert; 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci sfp_sm_mod_next(sfp, SFP_MOD_HPOWER, 0); 20278c2ecf20Sopenharmony_ci fallthrough; 20288c2ecf20Sopenharmony_ci case SFP_MOD_HPOWER: 20298c2ecf20Sopenharmony_ci /* Enable high power mode */ 20308c2ecf20Sopenharmony_ci err = sfp_sm_mod_hpower(sfp, true); 20318c2ecf20Sopenharmony_ci if (err < 0) { 20328c2ecf20Sopenharmony_ci if (err != -EAGAIN) { 20338c2ecf20Sopenharmony_ci sfp_module_remove(sfp->sfp_bus); 20348c2ecf20Sopenharmony_ci sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); 20358c2ecf20Sopenharmony_ci } else { 20368c2ecf20Sopenharmony_ci sfp_sm_set_timer(sfp, T_PROBE_RETRY_INIT); 20378c2ecf20Sopenharmony_ci } 20388c2ecf20Sopenharmony_ci break; 20398c2ecf20Sopenharmony_ci } 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci sfp_sm_mod_next(sfp, SFP_MOD_WAITPWR, T_HPOWER_LEVEL); 20428c2ecf20Sopenharmony_ci break; 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci case SFP_MOD_WAITPWR: 20458c2ecf20Sopenharmony_ci /* Wait for T_HPOWER_LEVEL to time out */ 20468c2ecf20Sopenharmony_ci if (event != SFP_E_TIMEOUT) 20478c2ecf20Sopenharmony_ci break; 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci insert: 20508c2ecf20Sopenharmony_ci sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0); 20518c2ecf20Sopenharmony_ci break; 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci case SFP_MOD_PRESENT: 20548c2ecf20Sopenharmony_ci case SFP_MOD_ERROR: 20558c2ecf20Sopenharmony_ci break; 20568c2ecf20Sopenharmony_ci } 20578c2ecf20Sopenharmony_ci} 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_cistatic void sfp_sm_main(struct sfp *sfp, unsigned int event) 20608c2ecf20Sopenharmony_ci{ 20618c2ecf20Sopenharmony_ci unsigned long timeout; 20628c2ecf20Sopenharmony_ci int ret; 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci /* Some events are global */ 20658c2ecf20Sopenharmony_ci if (sfp->sm_state != SFP_S_DOWN && 20668c2ecf20Sopenharmony_ci (sfp->sm_mod_state != SFP_MOD_PRESENT || 20678c2ecf20Sopenharmony_ci sfp->sm_dev_state != SFP_DEV_UP)) { 20688c2ecf20Sopenharmony_ci if (sfp->sm_state == SFP_S_LINK_UP && 20698c2ecf20Sopenharmony_ci sfp->sm_dev_state == SFP_DEV_UP) 20708c2ecf20Sopenharmony_ci sfp_sm_link_down(sfp); 20718c2ecf20Sopenharmony_ci if (sfp->sm_state > SFP_S_INIT) 20728c2ecf20Sopenharmony_ci sfp_module_stop(sfp->sfp_bus); 20738c2ecf20Sopenharmony_ci if (sfp->mod_phy) 20748c2ecf20Sopenharmony_ci sfp_sm_phy_detach(sfp); 20758c2ecf20Sopenharmony_ci sfp_module_tx_disable(sfp); 20768c2ecf20Sopenharmony_ci sfp_soft_stop_poll(sfp); 20778c2ecf20Sopenharmony_ci sfp_sm_next(sfp, SFP_S_DOWN, 0); 20788c2ecf20Sopenharmony_ci return; 20798c2ecf20Sopenharmony_ci } 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci /* The main state machine */ 20828c2ecf20Sopenharmony_ci switch (sfp->sm_state) { 20838c2ecf20Sopenharmony_ci case SFP_S_DOWN: 20848c2ecf20Sopenharmony_ci if (sfp->sm_mod_state != SFP_MOD_PRESENT || 20858c2ecf20Sopenharmony_ci sfp->sm_dev_state != SFP_DEV_UP) 20868c2ecf20Sopenharmony_ci break; 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci if (!(sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE)) 20898c2ecf20Sopenharmony_ci sfp_soft_start_poll(sfp); 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci sfp_module_tx_enable(sfp); 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci /* Initialise the fault clearance retries */ 20948c2ecf20Sopenharmony_ci sfp->sm_fault_retries = N_FAULT_INIT; 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci /* We need to check the TX_FAULT state, which is not defined 20978c2ecf20Sopenharmony_ci * while TX_DISABLE is asserted. The earliest we want to do 20988c2ecf20Sopenharmony_ci * anything (such as probe for a PHY) is 50ms. 20998c2ecf20Sopenharmony_ci */ 21008c2ecf20Sopenharmony_ci sfp_sm_next(sfp, SFP_S_WAIT, T_WAIT); 21018c2ecf20Sopenharmony_ci break; 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci case SFP_S_WAIT: 21048c2ecf20Sopenharmony_ci if (event != SFP_E_TIMEOUT) 21058c2ecf20Sopenharmony_ci break; 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci if (sfp->state & SFP_F_TX_FAULT) { 21088c2ecf20Sopenharmony_ci /* Wait up to t_init (SFF-8472) or t_start_up (SFF-8431) 21098c2ecf20Sopenharmony_ci * from the TX_DISABLE deassertion for the module to 21108c2ecf20Sopenharmony_ci * initialise, which is indicated by TX_FAULT 21118c2ecf20Sopenharmony_ci * deasserting. 21128c2ecf20Sopenharmony_ci */ 21138c2ecf20Sopenharmony_ci timeout = sfp->module_t_start_up; 21148c2ecf20Sopenharmony_ci if (timeout > T_WAIT) 21158c2ecf20Sopenharmony_ci timeout -= T_WAIT; 21168c2ecf20Sopenharmony_ci else 21178c2ecf20Sopenharmony_ci timeout = 1; 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci sfp_sm_next(sfp, SFP_S_INIT, timeout); 21208c2ecf20Sopenharmony_ci } else { 21218c2ecf20Sopenharmony_ci /* TX_FAULT is not asserted, assume the module has 21228c2ecf20Sopenharmony_ci * finished initialising. 21238c2ecf20Sopenharmony_ci */ 21248c2ecf20Sopenharmony_ci goto init_done; 21258c2ecf20Sopenharmony_ci } 21268c2ecf20Sopenharmony_ci break; 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci case SFP_S_INIT: 21298c2ecf20Sopenharmony_ci if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT) { 21308c2ecf20Sopenharmony_ci /* TX_FAULT is still asserted after t_init or 21318c2ecf20Sopenharmony_ci * or t_start_up, so assume there is a fault. 21328c2ecf20Sopenharmony_ci */ 21338c2ecf20Sopenharmony_ci sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT, 21348c2ecf20Sopenharmony_ci sfp->sm_fault_retries == N_FAULT_INIT); 21358c2ecf20Sopenharmony_ci } else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) { 21368c2ecf20Sopenharmony_ci init_done: 21378c2ecf20Sopenharmony_ci sfp->sm_phy_retries = R_PHY_RETRY; 21388c2ecf20Sopenharmony_ci goto phy_probe; 21398c2ecf20Sopenharmony_ci } 21408c2ecf20Sopenharmony_ci break; 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci case SFP_S_INIT_PHY: 21438c2ecf20Sopenharmony_ci if (event != SFP_E_TIMEOUT) 21448c2ecf20Sopenharmony_ci break; 21458c2ecf20Sopenharmony_ci phy_probe: 21468c2ecf20Sopenharmony_ci /* TX_FAULT deasserted or we timed out with TX_FAULT 21478c2ecf20Sopenharmony_ci * clear. Probe for the PHY and check the LOS state. 21488c2ecf20Sopenharmony_ci */ 21498c2ecf20Sopenharmony_ci ret = sfp_sm_probe_for_phy(sfp); 21508c2ecf20Sopenharmony_ci if (ret == -ENODEV) { 21518c2ecf20Sopenharmony_ci if (--sfp->sm_phy_retries) { 21528c2ecf20Sopenharmony_ci sfp_sm_next(sfp, SFP_S_INIT_PHY, T_PHY_RETRY); 21538c2ecf20Sopenharmony_ci break; 21548c2ecf20Sopenharmony_ci } else { 21558c2ecf20Sopenharmony_ci dev_info(sfp->dev, "no PHY detected\n"); 21568c2ecf20Sopenharmony_ci } 21578c2ecf20Sopenharmony_ci } else if (ret) { 21588c2ecf20Sopenharmony_ci sfp_sm_next(sfp, SFP_S_FAIL, 0); 21598c2ecf20Sopenharmony_ci break; 21608c2ecf20Sopenharmony_ci } 21618c2ecf20Sopenharmony_ci if (sfp_module_start(sfp->sfp_bus)) { 21628c2ecf20Sopenharmony_ci sfp_sm_next(sfp, SFP_S_FAIL, 0); 21638c2ecf20Sopenharmony_ci break; 21648c2ecf20Sopenharmony_ci } 21658c2ecf20Sopenharmony_ci sfp_sm_link_check_los(sfp); 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci /* Reset the fault retry count */ 21688c2ecf20Sopenharmony_ci sfp->sm_fault_retries = N_FAULT; 21698c2ecf20Sopenharmony_ci break; 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci case SFP_S_INIT_TX_FAULT: 21728c2ecf20Sopenharmony_ci if (event == SFP_E_TIMEOUT) { 21738c2ecf20Sopenharmony_ci sfp_module_tx_fault_reset(sfp); 21748c2ecf20Sopenharmony_ci sfp_sm_next(sfp, SFP_S_INIT, sfp->module_t_start_up); 21758c2ecf20Sopenharmony_ci } 21768c2ecf20Sopenharmony_ci break; 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci case SFP_S_WAIT_LOS: 21798c2ecf20Sopenharmony_ci if (event == SFP_E_TX_FAULT) 21808c2ecf20Sopenharmony_ci sfp_sm_fault(sfp, SFP_S_TX_FAULT, true); 21818c2ecf20Sopenharmony_ci else if (sfp_los_event_inactive(sfp, event)) 21828c2ecf20Sopenharmony_ci sfp_sm_link_up(sfp); 21838c2ecf20Sopenharmony_ci break; 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci case SFP_S_LINK_UP: 21868c2ecf20Sopenharmony_ci if (event == SFP_E_TX_FAULT) { 21878c2ecf20Sopenharmony_ci sfp_sm_link_down(sfp); 21888c2ecf20Sopenharmony_ci sfp_sm_fault(sfp, SFP_S_TX_FAULT, true); 21898c2ecf20Sopenharmony_ci } else if (sfp_los_event_active(sfp, event)) { 21908c2ecf20Sopenharmony_ci sfp_sm_link_down(sfp); 21918c2ecf20Sopenharmony_ci sfp_sm_next(sfp, SFP_S_WAIT_LOS, 0); 21928c2ecf20Sopenharmony_ci } 21938c2ecf20Sopenharmony_ci break; 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci case SFP_S_TX_FAULT: 21968c2ecf20Sopenharmony_ci if (event == SFP_E_TIMEOUT) { 21978c2ecf20Sopenharmony_ci sfp_module_tx_fault_reset(sfp); 21988c2ecf20Sopenharmony_ci sfp_sm_next(sfp, SFP_S_REINIT, sfp->module_t_start_up); 21998c2ecf20Sopenharmony_ci } 22008c2ecf20Sopenharmony_ci break; 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci case SFP_S_REINIT: 22038c2ecf20Sopenharmony_ci if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT) { 22048c2ecf20Sopenharmony_ci sfp_sm_fault(sfp, SFP_S_TX_FAULT, false); 22058c2ecf20Sopenharmony_ci } else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) { 22068c2ecf20Sopenharmony_ci dev_info(sfp->dev, "module transmit fault recovered\n"); 22078c2ecf20Sopenharmony_ci sfp_sm_link_check_los(sfp); 22088c2ecf20Sopenharmony_ci } 22098c2ecf20Sopenharmony_ci break; 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci case SFP_S_TX_DISABLE: 22128c2ecf20Sopenharmony_ci break; 22138c2ecf20Sopenharmony_ci } 22148c2ecf20Sopenharmony_ci} 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_cistatic void sfp_sm_event(struct sfp *sfp, unsigned int event) 22178c2ecf20Sopenharmony_ci{ 22188c2ecf20Sopenharmony_ci mutex_lock(&sfp->sm_mutex); 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci dev_dbg(sfp->dev, "SM: enter %s:%s:%s event %s\n", 22218c2ecf20Sopenharmony_ci mod_state_to_str(sfp->sm_mod_state), 22228c2ecf20Sopenharmony_ci dev_state_to_str(sfp->sm_dev_state), 22238c2ecf20Sopenharmony_ci sm_state_to_str(sfp->sm_state), 22248c2ecf20Sopenharmony_ci event_to_str(event)); 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci sfp_sm_device(sfp, event); 22278c2ecf20Sopenharmony_ci sfp_sm_module(sfp, event); 22288c2ecf20Sopenharmony_ci sfp_sm_main(sfp, event); 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci dev_dbg(sfp->dev, "SM: exit %s:%s:%s\n", 22318c2ecf20Sopenharmony_ci mod_state_to_str(sfp->sm_mod_state), 22328c2ecf20Sopenharmony_ci dev_state_to_str(sfp->sm_dev_state), 22338c2ecf20Sopenharmony_ci sm_state_to_str(sfp->sm_state)); 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ci mutex_unlock(&sfp->sm_mutex); 22368c2ecf20Sopenharmony_ci} 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_cistatic void sfp_attach(struct sfp *sfp) 22398c2ecf20Sopenharmony_ci{ 22408c2ecf20Sopenharmony_ci sfp_sm_event(sfp, SFP_E_DEV_ATTACH); 22418c2ecf20Sopenharmony_ci} 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_cistatic void sfp_detach(struct sfp *sfp) 22448c2ecf20Sopenharmony_ci{ 22458c2ecf20Sopenharmony_ci sfp_sm_event(sfp, SFP_E_DEV_DETACH); 22468c2ecf20Sopenharmony_ci} 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_cistatic void sfp_start(struct sfp *sfp) 22498c2ecf20Sopenharmony_ci{ 22508c2ecf20Sopenharmony_ci sfp_sm_event(sfp, SFP_E_DEV_UP); 22518c2ecf20Sopenharmony_ci} 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_cistatic void sfp_stop(struct sfp *sfp) 22548c2ecf20Sopenharmony_ci{ 22558c2ecf20Sopenharmony_ci sfp_sm_event(sfp, SFP_E_DEV_DOWN); 22568c2ecf20Sopenharmony_ci} 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_cistatic int sfp_module_info(struct sfp *sfp, struct ethtool_modinfo *modinfo) 22598c2ecf20Sopenharmony_ci{ 22608c2ecf20Sopenharmony_ci /* locking... and check module is present */ 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci if (sfp->id.ext.sff8472_compliance && 22638c2ecf20Sopenharmony_ci !(sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE)) { 22648c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8472; 22658c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 22668c2ecf20Sopenharmony_ci } else { 22678c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8079; 22688c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; 22698c2ecf20Sopenharmony_ci } 22708c2ecf20Sopenharmony_ci return 0; 22718c2ecf20Sopenharmony_ci} 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_cistatic int sfp_module_eeprom(struct sfp *sfp, struct ethtool_eeprom *ee, 22748c2ecf20Sopenharmony_ci u8 *data) 22758c2ecf20Sopenharmony_ci{ 22768c2ecf20Sopenharmony_ci unsigned int first, last, len; 22778c2ecf20Sopenharmony_ci int ret; 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci if (ee->len == 0) 22808c2ecf20Sopenharmony_ci return -EINVAL; 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci first = ee->offset; 22838c2ecf20Sopenharmony_ci last = ee->offset + ee->len; 22848c2ecf20Sopenharmony_ci if (first < ETH_MODULE_SFF_8079_LEN) { 22858c2ecf20Sopenharmony_ci len = min_t(unsigned int, last, ETH_MODULE_SFF_8079_LEN); 22868c2ecf20Sopenharmony_ci len -= first; 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_ci ret = sfp_read(sfp, false, first, data, len); 22898c2ecf20Sopenharmony_ci if (ret < 0) 22908c2ecf20Sopenharmony_ci return ret; 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_ci first += len; 22938c2ecf20Sopenharmony_ci data += len; 22948c2ecf20Sopenharmony_ci } 22958c2ecf20Sopenharmony_ci if (first < ETH_MODULE_SFF_8472_LEN && last > ETH_MODULE_SFF_8079_LEN) { 22968c2ecf20Sopenharmony_ci len = min_t(unsigned int, last, ETH_MODULE_SFF_8472_LEN); 22978c2ecf20Sopenharmony_ci len -= first; 22988c2ecf20Sopenharmony_ci first -= ETH_MODULE_SFF_8079_LEN; 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_ci ret = sfp_read(sfp, true, first, data, len); 23018c2ecf20Sopenharmony_ci if (ret < 0) 23028c2ecf20Sopenharmony_ci return ret; 23038c2ecf20Sopenharmony_ci } 23048c2ecf20Sopenharmony_ci return 0; 23058c2ecf20Sopenharmony_ci} 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_cistatic const struct sfp_socket_ops sfp_module_ops = { 23088c2ecf20Sopenharmony_ci .attach = sfp_attach, 23098c2ecf20Sopenharmony_ci .detach = sfp_detach, 23108c2ecf20Sopenharmony_ci .start = sfp_start, 23118c2ecf20Sopenharmony_ci .stop = sfp_stop, 23128c2ecf20Sopenharmony_ci .module_info = sfp_module_info, 23138c2ecf20Sopenharmony_ci .module_eeprom = sfp_module_eeprom, 23148c2ecf20Sopenharmony_ci}; 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_cistatic void sfp_timeout(struct work_struct *work) 23178c2ecf20Sopenharmony_ci{ 23188c2ecf20Sopenharmony_ci struct sfp *sfp = container_of(work, struct sfp, timeout.work); 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_ci rtnl_lock(); 23218c2ecf20Sopenharmony_ci sfp_sm_event(sfp, SFP_E_TIMEOUT); 23228c2ecf20Sopenharmony_ci rtnl_unlock(); 23238c2ecf20Sopenharmony_ci} 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_cistatic void sfp_check_state(struct sfp *sfp) 23268c2ecf20Sopenharmony_ci{ 23278c2ecf20Sopenharmony_ci unsigned int state, i, changed; 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci mutex_lock(&sfp->st_mutex); 23308c2ecf20Sopenharmony_ci state = sfp_get_state(sfp); 23318c2ecf20Sopenharmony_ci changed = state ^ sfp->state; 23328c2ecf20Sopenharmony_ci if (sfp->tx_fault_ignore) 23338c2ecf20Sopenharmony_ci changed &= SFP_F_PRESENT | SFP_F_LOS; 23348c2ecf20Sopenharmony_ci else 23358c2ecf20Sopenharmony_ci changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT; 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci for (i = 0; i < GPIO_MAX; i++) 23388c2ecf20Sopenharmony_ci if (changed & BIT(i)) 23398c2ecf20Sopenharmony_ci dev_dbg(sfp->dev, "%s %u -> %u\n", gpio_of_names[i], 23408c2ecf20Sopenharmony_ci !!(sfp->state & BIT(i)), !!(state & BIT(i))); 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci state |= sfp->state & (SFP_F_TX_DISABLE | SFP_F_RATE_SELECT); 23438c2ecf20Sopenharmony_ci sfp->state = state; 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci rtnl_lock(); 23468c2ecf20Sopenharmony_ci if (changed & SFP_F_PRESENT) 23478c2ecf20Sopenharmony_ci sfp_sm_event(sfp, state & SFP_F_PRESENT ? 23488c2ecf20Sopenharmony_ci SFP_E_INSERT : SFP_E_REMOVE); 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci if (changed & SFP_F_TX_FAULT) 23518c2ecf20Sopenharmony_ci sfp_sm_event(sfp, state & SFP_F_TX_FAULT ? 23528c2ecf20Sopenharmony_ci SFP_E_TX_FAULT : SFP_E_TX_CLEAR); 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci if (changed & SFP_F_LOS) 23558c2ecf20Sopenharmony_ci sfp_sm_event(sfp, state & SFP_F_LOS ? 23568c2ecf20Sopenharmony_ci SFP_E_LOS_HIGH : SFP_E_LOS_LOW); 23578c2ecf20Sopenharmony_ci rtnl_unlock(); 23588c2ecf20Sopenharmony_ci mutex_unlock(&sfp->st_mutex); 23598c2ecf20Sopenharmony_ci} 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_cistatic irqreturn_t sfp_irq(int irq, void *data) 23628c2ecf20Sopenharmony_ci{ 23638c2ecf20Sopenharmony_ci struct sfp *sfp = data; 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci sfp_check_state(sfp); 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci return IRQ_HANDLED; 23688c2ecf20Sopenharmony_ci} 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_cistatic void sfp_poll(struct work_struct *work) 23718c2ecf20Sopenharmony_ci{ 23728c2ecf20Sopenharmony_ci struct sfp *sfp = container_of(work, struct sfp, poll.work); 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ci sfp_check_state(sfp); 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) || 23778c2ecf20Sopenharmony_ci sfp->need_poll) 23788c2ecf20Sopenharmony_ci mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); 23798c2ecf20Sopenharmony_ci} 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_cistatic struct sfp *sfp_alloc(struct device *dev) 23828c2ecf20Sopenharmony_ci{ 23838c2ecf20Sopenharmony_ci struct sfp *sfp; 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_ci sfp = kzalloc(sizeof(*sfp), GFP_KERNEL); 23868c2ecf20Sopenharmony_ci if (!sfp) 23878c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci sfp->dev = dev; 23908c2ecf20Sopenharmony_ci sfp->i2c_block_size = SFP_EEPROM_BLOCK_SIZE; 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci mutex_init(&sfp->sm_mutex); 23938c2ecf20Sopenharmony_ci mutex_init(&sfp->st_mutex); 23948c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&sfp->poll, sfp_poll); 23958c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&sfp->timeout, sfp_timeout); 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci sfp_hwmon_init(sfp); 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci return sfp; 24008c2ecf20Sopenharmony_ci} 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_cistatic void sfp_cleanup(void *data) 24038c2ecf20Sopenharmony_ci{ 24048c2ecf20Sopenharmony_ci struct sfp *sfp = data; 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_ci sfp_hwmon_exit(sfp); 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&sfp->poll); 24098c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&sfp->timeout); 24108c2ecf20Sopenharmony_ci if (sfp->i2c_mii) { 24118c2ecf20Sopenharmony_ci mdiobus_unregister(sfp->i2c_mii); 24128c2ecf20Sopenharmony_ci mdiobus_free(sfp->i2c_mii); 24138c2ecf20Sopenharmony_ci } 24148c2ecf20Sopenharmony_ci if (sfp->i2c) 24158c2ecf20Sopenharmony_ci i2c_put_adapter(sfp->i2c); 24168c2ecf20Sopenharmony_ci kfree(sfp); 24178c2ecf20Sopenharmony_ci} 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_cistatic int sfp_probe(struct platform_device *pdev) 24208c2ecf20Sopenharmony_ci{ 24218c2ecf20Sopenharmony_ci const struct sff_data *sff; 24228c2ecf20Sopenharmony_ci struct i2c_adapter *i2c; 24238c2ecf20Sopenharmony_ci char *sfp_irq_name; 24248c2ecf20Sopenharmony_ci struct sfp *sfp; 24258c2ecf20Sopenharmony_ci int err, i; 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci sfp = sfp_alloc(&pdev->dev); 24288c2ecf20Sopenharmony_ci if (IS_ERR(sfp)) 24298c2ecf20Sopenharmony_ci return PTR_ERR(sfp); 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, sfp); 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci err = devm_add_action_or_reset(sfp->dev, sfp_cleanup, sfp); 24348c2ecf20Sopenharmony_ci if (err < 0) 24358c2ecf20Sopenharmony_ci return err; 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci sff = sfp->type = &sfp_data; 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_ci if (pdev->dev.of_node) { 24408c2ecf20Sopenharmony_ci struct device_node *node = pdev->dev.of_node; 24418c2ecf20Sopenharmony_ci const struct of_device_id *id; 24428c2ecf20Sopenharmony_ci struct device_node *np; 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci id = of_match_node(sfp_of_match, node); 24458c2ecf20Sopenharmony_ci if (WARN_ON(!id)) 24468c2ecf20Sopenharmony_ci return -EINVAL; 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_ci sff = sfp->type = id->data; 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ci np = of_parse_phandle(node, "i2c-bus", 0); 24518c2ecf20Sopenharmony_ci if (!np) { 24528c2ecf20Sopenharmony_ci dev_err(sfp->dev, "missing 'i2c-bus' property\n"); 24538c2ecf20Sopenharmony_ci return -ENODEV; 24548c2ecf20Sopenharmony_ci } 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci i2c = of_find_i2c_adapter_by_node(np); 24578c2ecf20Sopenharmony_ci of_node_put(np); 24588c2ecf20Sopenharmony_ci } else if (has_acpi_companion(&pdev->dev)) { 24598c2ecf20Sopenharmony_ci struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); 24608c2ecf20Sopenharmony_ci struct fwnode_handle *fw = acpi_fwnode_handle(adev); 24618c2ecf20Sopenharmony_ci struct fwnode_reference_args args; 24628c2ecf20Sopenharmony_ci struct acpi_handle *acpi_handle; 24638c2ecf20Sopenharmony_ci int ret; 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_ci ret = acpi_node_get_property_reference(fw, "i2c-bus", 0, &args); 24668c2ecf20Sopenharmony_ci if (ret || !is_acpi_device_node(args.fwnode)) { 24678c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "missing 'i2c-bus' property\n"); 24688c2ecf20Sopenharmony_ci return -ENODEV; 24698c2ecf20Sopenharmony_ci } 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci acpi_handle = ACPI_HANDLE_FWNODE(args.fwnode); 24728c2ecf20Sopenharmony_ci i2c = i2c_acpi_find_adapter_by_handle(acpi_handle); 24738c2ecf20Sopenharmony_ci } else { 24748c2ecf20Sopenharmony_ci return -EINVAL; 24758c2ecf20Sopenharmony_ci } 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_ci if (!i2c) 24788c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 24798c2ecf20Sopenharmony_ci 24808c2ecf20Sopenharmony_ci err = sfp_i2c_configure(sfp, i2c); 24818c2ecf20Sopenharmony_ci if (err < 0) { 24828c2ecf20Sopenharmony_ci i2c_put_adapter(i2c); 24838c2ecf20Sopenharmony_ci return err; 24848c2ecf20Sopenharmony_ci } 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci for (i = 0; i < GPIO_MAX; i++) 24878c2ecf20Sopenharmony_ci if (sff->gpios & BIT(i)) { 24888c2ecf20Sopenharmony_ci sfp->gpio[i] = devm_gpiod_get_optional(sfp->dev, 24898c2ecf20Sopenharmony_ci gpio_of_names[i], gpio_flags[i]); 24908c2ecf20Sopenharmony_ci if (IS_ERR(sfp->gpio[i])) 24918c2ecf20Sopenharmony_ci return PTR_ERR(sfp->gpio[i]); 24928c2ecf20Sopenharmony_ci } 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci sfp->get_state = sfp_gpio_get_state; 24958c2ecf20Sopenharmony_ci sfp->set_state = sfp_gpio_set_state; 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci /* Modules that have no detect signal are always present */ 24988c2ecf20Sopenharmony_ci if (!(sfp->gpio[GPIO_MODDEF0])) 24998c2ecf20Sopenharmony_ci sfp->get_state = sff_gpio_get_state; 25008c2ecf20Sopenharmony_ci 25018c2ecf20Sopenharmony_ci device_property_read_u32(&pdev->dev, "maximum-power-milliwatt", 25028c2ecf20Sopenharmony_ci &sfp->max_power_mW); 25038c2ecf20Sopenharmony_ci if (!sfp->max_power_mW) 25048c2ecf20Sopenharmony_ci sfp->max_power_mW = 1000; 25058c2ecf20Sopenharmony_ci 25068c2ecf20Sopenharmony_ci dev_info(sfp->dev, "Host maximum power %u.%uW\n", 25078c2ecf20Sopenharmony_ci sfp->max_power_mW / 1000, (sfp->max_power_mW / 100) % 10); 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_ci /* Get the initial state, and always signal TX disable, 25108c2ecf20Sopenharmony_ci * since the network interface will not be up. 25118c2ecf20Sopenharmony_ci */ 25128c2ecf20Sopenharmony_ci sfp->state = sfp_get_state(sfp) | SFP_F_TX_DISABLE; 25138c2ecf20Sopenharmony_ci 25148c2ecf20Sopenharmony_ci if (sfp->gpio[GPIO_RATE_SELECT] && 25158c2ecf20Sopenharmony_ci gpiod_get_value_cansleep(sfp->gpio[GPIO_RATE_SELECT])) 25168c2ecf20Sopenharmony_ci sfp->state |= SFP_F_RATE_SELECT; 25178c2ecf20Sopenharmony_ci sfp_set_state(sfp, sfp->state); 25188c2ecf20Sopenharmony_ci sfp_module_tx_disable(sfp); 25198c2ecf20Sopenharmony_ci if (sfp->state & SFP_F_PRESENT) { 25208c2ecf20Sopenharmony_ci rtnl_lock(); 25218c2ecf20Sopenharmony_ci sfp_sm_event(sfp, SFP_E_INSERT); 25228c2ecf20Sopenharmony_ci rtnl_unlock(); 25238c2ecf20Sopenharmony_ci } 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci for (i = 0; i < GPIO_MAX; i++) { 25268c2ecf20Sopenharmony_ci if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i]) 25278c2ecf20Sopenharmony_ci continue; 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci sfp->gpio_irq[i] = gpiod_to_irq(sfp->gpio[i]); 25308c2ecf20Sopenharmony_ci if (sfp->gpio_irq[i] < 0) { 25318c2ecf20Sopenharmony_ci sfp->gpio_irq[i] = 0; 25328c2ecf20Sopenharmony_ci sfp->need_poll = true; 25338c2ecf20Sopenharmony_ci continue; 25348c2ecf20Sopenharmony_ci } 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci sfp_irq_name = devm_kasprintf(sfp->dev, GFP_KERNEL, 25378c2ecf20Sopenharmony_ci "%s-%s", dev_name(sfp->dev), 25388c2ecf20Sopenharmony_ci gpio_of_names[i]); 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci if (!sfp_irq_name) 25418c2ecf20Sopenharmony_ci return -ENOMEM; 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci err = devm_request_threaded_irq(sfp->dev, sfp->gpio_irq[i], 25448c2ecf20Sopenharmony_ci NULL, sfp_irq, 25458c2ecf20Sopenharmony_ci IRQF_ONESHOT | 25468c2ecf20Sopenharmony_ci IRQF_TRIGGER_RISING | 25478c2ecf20Sopenharmony_ci IRQF_TRIGGER_FALLING, 25488c2ecf20Sopenharmony_ci sfp_irq_name, sfp); 25498c2ecf20Sopenharmony_ci if (err) { 25508c2ecf20Sopenharmony_ci sfp->gpio_irq[i] = 0; 25518c2ecf20Sopenharmony_ci sfp->need_poll = true; 25528c2ecf20Sopenharmony_ci } 25538c2ecf20Sopenharmony_ci } 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci if (sfp->need_poll) 25568c2ecf20Sopenharmony_ci mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_ci /* We could have an issue in cases no Tx disable pin is available or 25598c2ecf20Sopenharmony_ci * wired as modules using a laser as their light source will continue to 25608c2ecf20Sopenharmony_ci * be active when the fiber is removed. This could be a safety issue and 25618c2ecf20Sopenharmony_ci * we should at least warn the user about that. 25628c2ecf20Sopenharmony_ci */ 25638c2ecf20Sopenharmony_ci if (!sfp->gpio[GPIO_TX_DISABLE]) 25648c2ecf20Sopenharmony_ci dev_warn(sfp->dev, 25658c2ecf20Sopenharmony_ci "No tx_disable pin: SFP modules will always be emitting.\n"); 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci sfp->sfp_bus = sfp_register_socket(sfp->dev, sfp, &sfp_module_ops); 25688c2ecf20Sopenharmony_ci if (!sfp->sfp_bus) 25698c2ecf20Sopenharmony_ci return -ENOMEM; 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci return 0; 25728c2ecf20Sopenharmony_ci} 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_cistatic int sfp_remove(struct platform_device *pdev) 25758c2ecf20Sopenharmony_ci{ 25768c2ecf20Sopenharmony_ci struct sfp *sfp = platform_get_drvdata(pdev); 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci sfp_unregister_socket(sfp->sfp_bus); 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci rtnl_lock(); 25818c2ecf20Sopenharmony_ci sfp_sm_event(sfp, SFP_E_REMOVE); 25828c2ecf20Sopenharmony_ci rtnl_unlock(); 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci return 0; 25858c2ecf20Sopenharmony_ci} 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_cistatic void sfp_shutdown(struct platform_device *pdev) 25888c2ecf20Sopenharmony_ci{ 25898c2ecf20Sopenharmony_ci struct sfp *sfp = platform_get_drvdata(pdev); 25908c2ecf20Sopenharmony_ci int i; 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci for (i = 0; i < GPIO_MAX; i++) { 25938c2ecf20Sopenharmony_ci if (!sfp->gpio_irq[i]) 25948c2ecf20Sopenharmony_ci continue; 25958c2ecf20Sopenharmony_ci 25968c2ecf20Sopenharmony_ci devm_free_irq(sfp->dev, sfp->gpio_irq[i], sfp); 25978c2ecf20Sopenharmony_ci } 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&sfp->poll); 26008c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&sfp->timeout); 26018c2ecf20Sopenharmony_ci} 26028c2ecf20Sopenharmony_ci 26038c2ecf20Sopenharmony_cistatic struct platform_driver sfp_driver = { 26048c2ecf20Sopenharmony_ci .probe = sfp_probe, 26058c2ecf20Sopenharmony_ci .remove = sfp_remove, 26068c2ecf20Sopenharmony_ci .shutdown = sfp_shutdown, 26078c2ecf20Sopenharmony_ci .driver = { 26088c2ecf20Sopenharmony_ci .name = "sfp", 26098c2ecf20Sopenharmony_ci .of_match_table = sfp_of_match, 26108c2ecf20Sopenharmony_ci }, 26118c2ecf20Sopenharmony_ci}; 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_cistatic int sfp_init(void) 26148c2ecf20Sopenharmony_ci{ 26158c2ecf20Sopenharmony_ci poll_jiffies = msecs_to_jiffies(100); 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_ci return platform_driver_register(&sfp_driver); 26188c2ecf20Sopenharmony_ci} 26198c2ecf20Sopenharmony_cimodule_init(sfp_init); 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_cistatic void sfp_exit(void) 26228c2ecf20Sopenharmony_ci{ 26238c2ecf20Sopenharmony_ci platform_driver_unregister(&sfp_driver); 26248c2ecf20Sopenharmony_ci} 26258c2ecf20Sopenharmony_cimodule_exit(sfp_exit); 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:sfp"); 26288c2ecf20Sopenharmony_ciMODULE_AUTHOR("Russell King"); 26298c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 2630