18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0+ */
28c2ecf20Sopenharmony_ci/* Copyright (C) 2018 Microchip Technology Inc. */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/ptp_clock_kernel.h>
78c2ecf20Sopenharmony_ci#include <linux/module.h>
88c2ecf20Sopenharmony_ci#include <linux/pci.h>
98c2ecf20Sopenharmony_ci#include <linux/net_tstamp.h>
108c2ecf20Sopenharmony_ci#include "lan743x_main.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include "lan743x_ptp.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define LAN743X_LED0_ENABLE		20	/* LED0 offset in HW_CFG */
158c2ecf20Sopenharmony_ci#define LAN743X_LED_ENABLE(pin)		BIT(LAN743X_LED0_ENABLE + (pin))
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB		(31249999)
188c2ecf20Sopenharmony_ci#define LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM	(2047999934)
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic bool lan743x_ptp_is_enabled(struct lan743x_adapter *adapter);
218c2ecf20Sopenharmony_cistatic void lan743x_ptp_enable(struct lan743x_adapter *adapter);
228c2ecf20Sopenharmony_cistatic void lan743x_ptp_disable(struct lan743x_adapter *adapter);
238c2ecf20Sopenharmony_cistatic void lan743x_ptp_reset(struct lan743x_adapter *adapter);
248c2ecf20Sopenharmony_cistatic void lan743x_ptp_clock_set(struct lan743x_adapter *adapter,
258c2ecf20Sopenharmony_ci				  u32 seconds, u32 nano_seconds,
268c2ecf20Sopenharmony_ci				  u32 sub_nano_seconds);
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ciint lan743x_gpio_init(struct lan743x_adapter *adapter)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	struct lan743x_gpio *gpio = &adapter->gpio;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	spin_lock_init(&gpio->gpio_lock);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	gpio->gpio_cfg0 = 0; /* set all direction to input, data = 0 */
358c2ecf20Sopenharmony_ci	gpio->gpio_cfg1 = 0x0FFF0000;/* disable all gpio, set to open drain */
368c2ecf20Sopenharmony_ci	gpio->gpio_cfg2 = 0;/* set all to 1588 low polarity level */
378c2ecf20Sopenharmony_ci	gpio->gpio_cfg3 = 0;/* disable all 1588 output */
388c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0);
398c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1);
408c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, GPIO_CFG2, gpio->gpio_cfg2);
418c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, GPIO_CFG3, gpio->gpio_cfg3);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	return 0;
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic void lan743x_ptp_wait_till_cmd_done(struct lan743x_adapter *adapter,
478c2ecf20Sopenharmony_ci					   u32 bit_mask)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	int timeout = 1000;
508c2ecf20Sopenharmony_ci	u32 data = 0;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	while (timeout &&
538c2ecf20Sopenharmony_ci	       (data = (lan743x_csr_read(adapter, PTP_CMD_CTL) &
548c2ecf20Sopenharmony_ci	       bit_mask))) {
558c2ecf20Sopenharmony_ci		usleep_range(1000, 20000);
568c2ecf20Sopenharmony_ci		timeout--;
578c2ecf20Sopenharmony_ci	}
588c2ecf20Sopenharmony_ci	if (data) {
598c2ecf20Sopenharmony_ci		netif_err(adapter, drv, adapter->netdev,
608c2ecf20Sopenharmony_ci			  "timeout waiting for cmd to be done, cmd = 0x%08X\n",
618c2ecf20Sopenharmony_ci			  bit_mask);
628c2ecf20Sopenharmony_ci	}
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic void lan743x_ptp_tx_ts_enqueue_ts(struct lan743x_adapter *adapter,
668c2ecf20Sopenharmony_ci					 u32 seconds, u32 nano_seconds,
678c2ecf20Sopenharmony_ci					 u32 header)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = &adapter->ptp;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	spin_lock_bh(&ptp->tx_ts_lock);
728c2ecf20Sopenharmony_ci	if (ptp->tx_ts_queue_size < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) {
738c2ecf20Sopenharmony_ci		ptp->tx_ts_seconds_queue[ptp->tx_ts_queue_size] = seconds;
748c2ecf20Sopenharmony_ci		ptp->tx_ts_nseconds_queue[ptp->tx_ts_queue_size] = nano_seconds;
758c2ecf20Sopenharmony_ci		ptp->tx_ts_header_queue[ptp->tx_ts_queue_size] = header;
768c2ecf20Sopenharmony_ci		ptp->tx_ts_queue_size++;
778c2ecf20Sopenharmony_ci	} else {
788c2ecf20Sopenharmony_ci		netif_err(adapter, drv, adapter->netdev,
798c2ecf20Sopenharmony_ci			  "tx ts queue overflow\n");
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci	spin_unlock_bh(&ptp->tx_ts_lock);
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic void lan743x_ptp_tx_ts_complete(struct lan743x_adapter *adapter)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = &adapter->ptp;
878c2ecf20Sopenharmony_ci	struct skb_shared_hwtstamps tstamps;
888c2ecf20Sopenharmony_ci	u32 header, nseconds, seconds;
898c2ecf20Sopenharmony_ci	bool ignore_sync = false;
908c2ecf20Sopenharmony_ci	struct sk_buff *skb;
918c2ecf20Sopenharmony_ci	int c, i;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	spin_lock_bh(&ptp->tx_ts_lock);
948c2ecf20Sopenharmony_ci	c = ptp->tx_ts_skb_queue_size;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	if (c > ptp->tx_ts_queue_size)
978c2ecf20Sopenharmony_ci		c = ptp->tx_ts_queue_size;
988c2ecf20Sopenharmony_ci	if (c <= 0)
998c2ecf20Sopenharmony_ci		goto done;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	for (i = 0; i < c; i++) {
1028c2ecf20Sopenharmony_ci		ignore_sync = ((ptp->tx_ts_ignore_sync_queue &
1038c2ecf20Sopenharmony_ci				BIT(i)) != 0);
1048c2ecf20Sopenharmony_ci		skb = ptp->tx_ts_skb_queue[i];
1058c2ecf20Sopenharmony_ci		nseconds = ptp->tx_ts_nseconds_queue[i];
1068c2ecf20Sopenharmony_ci		seconds = ptp->tx_ts_seconds_queue[i];
1078c2ecf20Sopenharmony_ci		header = ptp->tx_ts_header_queue[i];
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci		memset(&tstamps, 0, sizeof(tstamps));
1108c2ecf20Sopenharmony_ci		tstamps.hwtstamp = ktime_set(seconds, nseconds);
1118c2ecf20Sopenharmony_ci		if (!ignore_sync ||
1128c2ecf20Sopenharmony_ci		    ((header & PTP_TX_MSG_HEADER_MSG_TYPE_) !=
1138c2ecf20Sopenharmony_ci		    PTP_TX_MSG_HEADER_MSG_TYPE_SYNC_))
1148c2ecf20Sopenharmony_ci			skb_tstamp_tx(skb, &tstamps);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci		ptp->tx_ts_skb_queue[i] = NULL;
1198c2ecf20Sopenharmony_ci		ptp->tx_ts_seconds_queue[i] = 0;
1208c2ecf20Sopenharmony_ci		ptp->tx_ts_nseconds_queue[i] = 0;
1218c2ecf20Sopenharmony_ci		ptp->tx_ts_header_queue[i] = 0;
1228c2ecf20Sopenharmony_ci	}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	/* shift queue */
1258c2ecf20Sopenharmony_ci	ptp->tx_ts_ignore_sync_queue >>= c;
1268c2ecf20Sopenharmony_ci	for (i = c; i < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS; i++) {
1278c2ecf20Sopenharmony_ci		ptp->tx_ts_skb_queue[i - c] = ptp->tx_ts_skb_queue[i];
1288c2ecf20Sopenharmony_ci		ptp->tx_ts_seconds_queue[i - c] = ptp->tx_ts_seconds_queue[i];
1298c2ecf20Sopenharmony_ci		ptp->tx_ts_nseconds_queue[i - c] = ptp->tx_ts_nseconds_queue[i];
1308c2ecf20Sopenharmony_ci		ptp->tx_ts_header_queue[i - c] = ptp->tx_ts_header_queue[i];
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci		ptp->tx_ts_skb_queue[i] = NULL;
1338c2ecf20Sopenharmony_ci		ptp->tx_ts_seconds_queue[i] = 0;
1348c2ecf20Sopenharmony_ci		ptp->tx_ts_nseconds_queue[i] = 0;
1358c2ecf20Sopenharmony_ci		ptp->tx_ts_header_queue[i] = 0;
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci	ptp->tx_ts_skb_queue_size -= c;
1388c2ecf20Sopenharmony_ci	ptp->tx_ts_queue_size -= c;
1398c2ecf20Sopenharmony_cidone:
1408c2ecf20Sopenharmony_ci	ptp->pending_tx_timestamps -= c;
1418c2ecf20Sopenharmony_ci	spin_unlock_bh(&ptp->tx_ts_lock);
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic int lan743x_ptp_reserve_event_ch(struct lan743x_adapter *adapter,
1458c2ecf20Sopenharmony_ci					int event_channel)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = &adapter->ptp;
1488c2ecf20Sopenharmony_ci	int result = -ENODEV;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	mutex_lock(&ptp->command_lock);
1518c2ecf20Sopenharmony_ci	if (!(test_bit(event_channel, &ptp->used_event_ch))) {
1528c2ecf20Sopenharmony_ci		ptp->used_event_ch |= BIT(event_channel);
1538c2ecf20Sopenharmony_ci		result = event_channel;
1548c2ecf20Sopenharmony_ci	} else {
1558c2ecf20Sopenharmony_ci		netif_warn(adapter, drv, adapter->netdev,
1568c2ecf20Sopenharmony_ci			   "attempted to reserved a used event_channel = %d\n",
1578c2ecf20Sopenharmony_ci			   event_channel);
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci	mutex_unlock(&ptp->command_lock);
1608c2ecf20Sopenharmony_ci	return result;
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic void lan743x_ptp_release_event_ch(struct lan743x_adapter *adapter,
1648c2ecf20Sopenharmony_ci					 int event_channel)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = &adapter->ptp;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	mutex_lock(&ptp->command_lock);
1698c2ecf20Sopenharmony_ci	if (test_bit(event_channel, &ptp->used_event_ch)) {
1708c2ecf20Sopenharmony_ci		ptp->used_event_ch &= ~BIT(event_channel);
1718c2ecf20Sopenharmony_ci	} else {
1728c2ecf20Sopenharmony_ci		netif_warn(adapter, drv, adapter->netdev,
1738c2ecf20Sopenharmony_ci			   "attempted release on a not used event_channel = %d\n",
1748c2ecf20Sopenharmony_ci			   event_channel);
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci	mutex_unlock(&ptp->command_lock);
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic void lan743x_ptp_clock_get(struct lan743x_adapter *adapter,
1808c2ecf20Sopenharmony_ci				  u32 *seconds, u32 *nano_seconds,
1818c2ecf20Sopenharmony_ci				  u32 *sub_nano_seconds);
1828c2ecf20Sopenharmony_cistatic void lan743x_ptp_clock_step(struct lan743x_adapter *adapter,
1838c2ecf20Sopenharmony_ci				   s64 time_step_ns);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic void lan743x_led_mux_enable(struct lan743x_adapter *adapter,
1868c2ecf20Sopenharmony_ci				   int pin, bool enable)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = &adapter->ptp;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	if (ptp->leds_multiplexed &&
1918c2ecf20Sopenharmony_ci	    ptp->led_enabled[pin]) {
1928c2ecf20Sopenharmony_ci		u32 val = lan743x_csr_read(adapter, HW_CFG);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci		if (enable)
1958c2ecf20Sopenharmony_ci			val |= LAN743X_LED_ENABLE(pin);
1968c2ecf20Sopenharmony_ci		else
1978c2ecf20Sopenharmony_ci			val &= ~LAN743X_LED_ENABLE(pin);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter, HW_CFG, val);
2008c2ecf20Sopenharmony_ci	}
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_cistatic void lan743x_led_mux_save(struct lan743x_adapter *adapter)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = &adapter->ptp;
2068c2ecf20Sopenharmony_ci	u32 id_rev = adapter->csr.id_rev & ID_REV_ID_MASK_;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	if (id_rev == ID_REV_ID_LAN7430_) {
2098c2ecf20Sopenharmony_ci		int i;
2108c2ecf20Sopenharmony_ci		u32 val = lan743x_csr_read(adapter, HW_CFG);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci		for (i = 0; i < LAN7430_N_LED; i++) {
2138c2ecf20Sopenharmony_ci			bool led_enabled = (val & LAN743X_LED_ENABLE(i)) != 0;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci			ptp->led_enabled[i] = led_enabled;
2168c2ecf20Sopenharmony_ci		}
2178c2ecf20Sopenharmony_ci		ptp->leds_multiplexed = true;
2188c2ecf20Sopenharmony_ci	} else {
2198c2ecf20Sopenharmony_ci		ptp->leds_multiplexed = false;
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic void lan743x_led_mux_restore(struct lan743x_adapter *adapter)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	u32 id_rev = adapter->csr.id_rev & ID_REV_ID_MASK_;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	if (id_rev == ID_REV_ID_LAN7430_) {
2288c2ecf20Sopenharmony_ci		int i;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci		for (i = 0; i < LAN7430_N_LED; i++)
2318c2ecf20Sopenharmony_ci			lan743x_led_mux_enable(adapter, i, true);
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic int lan743x_gpio_rsrv_ptp_out(struct lan743x_adapter *adapter,
2368c2ecf20Sopenharmony_ci				     int pin, int event_channel)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	struct lan743x_gpio *gpio = &adapter->gpio;
2398c2ecf20Sopenharmony_ci	unsigned long irq_flags = 0;
2408c2ecf20Sopenharmony_ci	int bit_mask = BIT(pin);
2418c2ecf20Sopenharmony_ci	int ret = -EBUSY;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	spin_lock_irqsave(&gpio->gpio_lock, irq_flags);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	if (!(gpio->used_bits & bit_mask)) {
2468c2ecf20Sopenharmony_ci		gpio->used_bits |= bit_mask;
2478c2ecf20Sopenharmony_ci		gpio->output_bits |= bit_mask;
2488c2ecf20Sopenharmony_ci		gpio->ptp_bits |= bit_mask;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci		/* assign pin to GPIO function */
2518c2ecf20Sopenharmony_ci		lan743x_led_mux_enable(adapter, pin, false);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci		/* set as output, and zero initial value */
2548c2ecf20Sopenharmony_ci		gpio->gpio_cfg0 |= GPIO_CFG0_GPIO_DIR_BIT_(pin);
2558c2ecf20Sopenharmony_ci		gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DATA_BIT_(pin);
2568c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci		/* enable gpio, and set buffer type to push pull */
2598c2ecf20Sopenharmony_ci		gpio->gpio_cfg1 &= ~GPIO_CFG1_GPIOEN_BIT_(pin);
2608c2ecf20Sopenharmony_ci		gpio->gpio_cfg1 |= GPIO_CFG1_GPIOBUF_BIT_(pin);
2618c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci		/* set 1588 polarity to high */
2648c2ecf20Sopenharmony_ci		gpio->gpio_cfg2 |= GPIO_CFG2_1588_POL_BIT_(pin);
2658c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter, GPIO_CFG2, gpio->gpio_cfg2);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci		if (event_channel == 0) {
2688c2ecf20Sopenharmony_ci			/* use channel A */
2698c2ecf20Sopenharmony_ci			gpio->gpio_cfg3 &= ~GPIO_CFG3_1588_CH_SEL_BIT_(pin);
2708c2ecf20Sopenharmony_ci		} else {
2718c2ecf20Sopenharmony_ci			/* use channel B */
2728c2ecf20Sopenharmony_ci			gpio->gpio_cfg3 |= GPIO_CFG3_1588_CH_SEL_BIT_(pin);
2738c2ecf20Sopenharmony_ci		}
2748c2ecf20Sopenharmony_ci		gpio->gpio_cfg3 |= GPIO_CFG3_1588_OE_BIT_(pin);
2758c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter, GPIO_CFG3, gpio->gpio_cfg3);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci		ret = pin;
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&gpio->gpio_lock, irq_flags);
2808c2ecf20Sopenharmony_ci	return ret;
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic void lan743x_gpio_release(struct lan743x_adapter *adapter, int pin)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	struct lan743x_gpio *gpio = &adapter->gpio;
2868c2ecf20Sopenharmony_ci	unsigned long irq_flags = 0;
2878c2ecf20Sopenharmony_ci	int bit_mask = BIT(pin);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	spin_lock_irqsave(&gpio->gpio_lock, irq_flags);
2908c2ecf20Sopenharmony_ci	if (gpio->used_bits & bit_mask) {
2918c2ecf20Sopenharmony_ci		gpio->used_bits &= ~bit_mask;
2928c2ecf20Sopenharmony_ci		if (gpio->output_bits & bit_mask) {
2938c2ecf20Sopenharmony_ci			gpio->output_bits &= ~bit_mask;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci			if (gpio->ptp_bits & bit_mask) {
2968c2ecf20Sopenharmony_ci				gpio->ptp_bits &= ~bit_mask;
2978c2ecf20Sopenharmony_ci				/* disable ptp output */
2988c2ecf20Sopenharmony_ci				gpio->gpio_cfg3 &= ~GPIO_CFG3_1588_OE_BIT_(pin);
2998c2ecf20Sopenharmony_ci				lan743x_csr_write(adapter, GPIO_CFG3,
3008c2ecf20Sopenharmony_ci						  gpio->gpio_cfg3);
3018c2ecf20Sopenharmony_ci			}
3028c2ecf20Sopenharmony_ci			/* release gpio output */
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci			/* disable gpio */
3058c2ecf20Sopenharmony_ci			gpio->gpio_cfg1 |= GPIO_CFG1_GPIOEN_BIT_(pin);
3068c2ecf20Sopenharmony_ci			gpio->gpio_cfg1 &= ~GPIO_CFG1_GPIOBUF_BIT_(pin);
3078c2ecf20Sopenharmony_ci			lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci			/* reset back to input */
3108c2ecf20Sopenharmony_ci			gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DIR_BIT_(pin);
3118c2ecf20Sopenharmony_ci			gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DATA_BIT_(pin);
3128c2ecf20Sopenharmony_ci			lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci			/* assign pin to original function */
3158c2ecf20Sopenharmony_ci			lan743x_led_mux_enable(adapter, pin, true);
3168c2ecf20Sopenharmony_ci		}
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&gpio->gpio_lock, irq_flags);
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic int lan743x_ptpci_adjfine(struct ptp_clock_info *ptpci, long scaled_ppm)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp =
3248c2ecf20Sopenharmony_ci		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
3258c2ecf20Sopenharmony_ci	struct lan743x_adapter *adapter =
3268c2ecf20Sopenharmony_ci		container_of(ptp, struct lan743x_adapter, ptp);
3278c2ecf20Sopenharmony_ci	u32 lan743x_rate_adj = 0;
3288c2ecf20Sopenharmony_ci	bool positive = true;
3298c2ecf20Sopenharmony_ci	u64 u64_delta = 0;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	if ((scaled_ppm < (-LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM)) ||
3328c2ecf20Sopenharmony_ci	    scaled_ppm > LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM) {
3338c2ecf20Sopenharmony_ci		return -EINVAL;
3348c2ecf20Sopenharmony_ci	}
3358c2ecf20Sopenharmony_ci	if (scaled_ppm > 0) {
3368c2ecf20Sopenharmony_ci		u64_delta = (u64)scaled_ppm;
3378c2ecf20Sopenharmony_ci		positive = true;
3388c2ecf20Sopenharmony_ci	} else {
3398c2ecf20Sopenharmony_ci		u64_delta = (u64)(-scaled_ppm);
3408c2ecf20Sopenharmony_ci		positive = false;
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci	u64_delta = (u64_delta << 19);
3438c2ecf20Sopenharmony_ci	lan743x_rate_adj = div_u64(u64_delta, 1000000);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	if (positive)
3468c2ecf20Sopenharmony_ci		lan743x_rate_adj |= PTP_CLOCK_RATE_ADJ_DIR_;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, PTP_CLOCK_RATE_ADJ,
3498c2ecf20Sopenharmony_ci			  lan743x_rate_adj);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	return 0;
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cistatic int lan743x_ptpci_adjfreq(struct ptp_clock_info *ptpci, s32 delta_ppb)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp =
3578c2ecf20Sopenharmony_ci		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
3588c2ecf20Sopenharmony_ci	struct lan743x_adapter *adapter =
3598c2ecf20Sopenharmony_ci		container_of(ptp, struct lan743x_adapter, ptp);
3608c2ecf20Sopenharmony_ci	u32 lan743x_rate_adj = 0;
3618c2ecf20Sopenharmony_ci	bool positive = true;
3628c2ecf20Sopenharmony_ci	u32 u32_delta = 0;
3638c2ecf20Sopenharmony_ci	u64 u64_delta = 0;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	if ((delta_ppb < (-LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB)) ||
3668c2ecf20Sopenharmony_ci	    delta_ppb > LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB) {
3678c2ecf20Sopenharmony_ci		return -EINVAL;
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci	if (delta_ppb > 0) {
3708c2ecf20Sopenharmony_ci		u32_delta = (u32)delta_ppb;
3718c2ecf20Sopenharmony_ci		positive = true;
3728c2ecf20Sopenharmony_ci	} else {
3738c2ecf20Sopenharmony_ci		u32_delta = (u32)(-delta_ppb);
3748c2ecf20Sopenharmony_ci		positive = false;
3758c2ecf20Sopenharmony_ci	}
3768c2ecf20Sopenharmony_ci	u64_delta = (((u64)u32_delta) << 35);
3778c2ecf20Sopenharmony_ci	lan743x_rate_adj = div_u64(u64_delta, 1000000000);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	if (positive)
3808c2ecf20Sopenharmony_ci		lan743x_rate_adj |= PTP_CLOCK_RATE_ADJ_DIR_;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, PTP_CLOCK_RATE_ADJ,
3838c2ecf20Sopenharmony_ci			  lan743x_rate_adj);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	return 0;
3868c2ecf20Sopenharmony_ci}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_cistatic int lan743x_ptpci_adjtime(struct ptp_clock_info *ptpci, s64 delta)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp =
3918c2ecf20Sopenharmony_ci		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
3928c2ecf20Sopenharmony_ci	struct lan743x_adapter *adapter =
3938c2ecf20Sopenharmony_ci		container_of(ptp, struct lan743x_adapter, ptp);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	lan743x_ptp_clock_step(adapter, delta);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	return 0;
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic int lan743x_ptpci_gettime64(struct ptp_clock_info *ptpci,
4018c2ecf20Sopenharmony_ci				   struct timespec64 *ts)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp =
4048c2ecf20Sopenharmony_ci		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
4058c2ecf20Sopenharmony_ci	struct lan743x_adapter *adapter =
4068c2ecf20Sopenharmony_ci		container_of(ptp, struct lan743x_adapter, ptp);
4078c2ecf20Sopenharmony_ci	u32 nano_seconds = 0;
4088c2ecf20Sopenharmony_ci	u32 seconds = 0;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	lan743x_ptp_clock_get(adapter, &seconds, &nano_seconds, NULL);
4118c2ecf20Sopenharmony_ci	ts->tv_sec = seconds;
4128c2ecf20Sopenharmony_ci	ts->tv_nsec = nano_seconds;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	return 0;
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_cistatic int lan743x_ptpci_settime64(struct ptp_clock_info *ptpci,
4188c2ecf20Sopenharmony_ci				   const struct timespec64 *ts)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp =
4218c2ecf20Sopenharmony_ci		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
4228c2ecf20Sopenharmony_ci	struct lan743x_adapter *adapter =
4238c2ecf20Sopenharmony_ci		container_of(ptp, struct lan743x_adapter, ptp);
4248c2ecf20Sopenharmony_ci	u32 nano_seconds = 0;
4258c2ecf20Sopenharmony_ci	u32 seconds = 0;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	if (ts) {
4288c2ecf20Sopenharmony_ci		if (ts->tv_sec > 0xFFFFFFFFLL ||
4298c2ecf20Sopenharmony_ci		    ts->tv_sec < 0) {
4308c2ecf20Sopenharmony_ci			netif_warn(adapter, drv, adapter->netdev,
4318c2ecf20Sopenharmony_ci				   "ts->tv_sec out of range, %lld\n",
4328c2ecf20Sopenharmony_ci				   ts->tv_sec);
4338c2ecf20Sopenharmony_ci			return -ERANGE;
4348c2ecf20Sopenharmony_ci		}
4358c2ecf20Sopenharmony_ci		if (ts->tv_nsec >= 1000000000L ||
4368c2ecf20Sopenharmony_ci		    ts->tv_nsec < 0) {
4378c2ecf20Sopenharmony_ci			netif_warn(adapter, drv, adapter->netdev,
4388c2ecf20Sopenharmony_ci				   "ts->tv_nsec out of range, %ld\n",
4398c2ecf20Sopenharmony_ci				   ts->tv_nsec);
4408c2ecf20Sopenharmony_ci			return -ERANGE;
4418c2ecf20Sopenharmony_ci		}
4428c2ecf20Sopenharmony_ci		seconds = ts->tv_sec;
4438c2ecf20Sopenharmony_ci		nano_seconds = ts->tv_nsec;
4448c2ecf20Sopenharmony_ci		lan743x_ptp_clock_set(adapter, seconds, nano_seconds, 0);
4458c2ecf20Sopenharmony_ci	} else {
4468c2ecf20Sopenharmony_ci		netif_warn(adapter, drv, adapter->netdev, "ts == NULL\n");
4478c2ecf20Sopenharmony_ci		return -EINVAL;
4488c2ecf20Sopenharmony_ci	}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	return 0;
4518c2ecf20Sopenharmony_ci}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_cistatic void lan743x_ptp_perout_off(struct lan743x_adapter *adapter,
4548c2ecf20Sopenharmony_ci				   unsigned int index)
4558c2ecf20Sopenharmony_ci{
4568c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = &adapter->ptp;
4578c2ecf20Sopenharmony_ci	u32 general_config = 0;
4588c2ecf20Sopenharmony_ci	struct lan743x_ptp_perout *perout = &ptp->perout[index];
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	if (perout->gpio_pin >= 0) {
4618c2ecf20Sopenharmony_ci		lan743x_gpio_release(adapter, perout->gpio_pin);
4628c2ecf20Sopenharmony_ci		perout->gpio_pin = -1;
4638c2ecf20Sopenharmony_ci	}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	if (perout->event_ch >= 0) {
4668c2ecf20Sopenharmony_ci		/* set target to far in the future, effectively disabling it */
4678c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter,
4688c2ecf20Sopenharmony_ci				  PTP_CLOCK_TARGET_SEC_X(perout->event_ch),
4698c2ecf20Sopenharmony_ci				  0xFFFF0000);
4708c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter,
4718c2ecf20Sopenharmony_ci				  PTP_CLOCK_TARGET_NS_X(perout->event_ch),
4728c2ecf20Sopenharmony_ci				  0);
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci		general_config = lan743x_csr_read(adapter, PTP_GENERAL_CONFIG);
4758c2ecf20Sopenharmony_ci		general_config |= PTP_GENERAL_CONFIG_RELOAD_ADD_X_
4768c2ecf20Sopenharmony_ci				  (perout->event_ch);
4778c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter, PTP_GENERAL_CONFIG, general_config);
4788c2ecf20Sopenharmony_ci		lan743x_ptp_release_event_ch(adapter, perout->event_ch);
4798c2ecf20Sopenharmony_ci		perout->event_ch = -1;
4808c2ecf20Sopenharmony_ci	}
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_cistatic int lan743x_ptp_perout(struct lan743x_adapter *adapter, int on,
4848c2ecf20Sopenharmony_ci			      struct ptp_perout_request *perout_request)
4858c2ecf20Sopenharmony_ci{
4868c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = &adapter->ptp;
4878c2ecf20Sopenharmony_ci	u32 period_sec = 0, period_nsec = 0;
4888c2ecf20Sopenharmony_ci	u32 start_sec = 0, start_nsec = 0;
4898c2ecf20Sopenharmony_ci	u32 general_config = 0;
4908c2ecf20Sopenharmony_ci	int pulse_width = 0;
4918c2ecf20Sopenharmony_ci	int perout_pin = 0;
4928c2ecf20Sopenharmony_ci	unsigned int index = perout_request->index;
4938c2ecf20Sopenharmony_ci	struct lan743x_ptp_perout *perout = &ptp->perout[index];
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	/* Reject requests with unsupported flags */
4968c2ecf20Sopenharmony_ci	if (perout_request->flags)
4978c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	if (on) {
5008c2ecf20Sopenharmony_ci		perout_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_PEROUT,
5018c2ecf20Sopenharmony_ci					  perout_request->index);
5028c2ecf20Sopenharmony_ci		if (perout_pin < 0)
5038c2ecf20Sopenharmony_ci			return -EBUSY;
5048c2ecf20Sopenharmony_ci	} else {
5058c2ecf20Sopenharmony_ci		lan743x_ptp_perout_off(adapter, index);
5068c2ecf20Sopenharmony_ci		return 0;
5078c2ecf20Sopenharmony_ci	}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	if (perout->event_ch >= 0 ||
5108c2ecf20Sopenharmony_ci	    perout->gpio_pin >= 0) {
5118c2ecf20Sopenharmony_ci		/* already on, turn off first */
5128c2ecf20Sopenharmony_ci		lan743x_ptp_perout_off(adapter, index);
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	perout->event_ch = lan743x_ptp_reserve_event_ch(adapter, index);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	if (perout->event_ch < 0) {
5188c2ecf20Sopenharmony_ci		netif_warn(adapter, drv, adapter->netdev,
5198c2ecf20Sopenharmony_ci			   "Failed to reserve event channel %d for PEROUT\n",
5208c2ecf20Sopenharmony_ci			   index);
5218c2ecf20Sopenharmony_ci		goto failed;
5228c2ecf20Sopenharmony_ci	}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	perout->gpio_pin = lan743x_gpio_rsrv_ptp_out(adapter,
5258c2ecf20Sopenharmony_ci						     perout_pin,
5268c2ecf20Sopenharmony_ci						     perout->event_ch);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	if (perout->gpio_pin < 0) {
5298c2ecf20Sopenharmony_ci		netif_warn(adapter, drv, adapter->netdev,
5308c2ecf20Sopenharmony_ci			   "Failed to reserve gpio %d for PEROUT\n",
5318c2ecf20Sopenharmony_ci			   perout_pin);
5328c2ecf20Sopenharmony_ci		goto failed;
5338c2ecf20Sopenharmony_ci	}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	start_sec = perout_request->start.sec;
5368c2ecf20Sopenharmony_ci	start_sec += perout_request->start.nsec / 1000000000;
5378c2ecf20Sopenharmony_ci	start_nsec = perout_request->start.nsec % 1000000000;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	period_sec = perout_request->period.sec;
5408c2ecf20Sopenharmony_ci	period_sec += perout_request->period.nsec / 1000000000;
5418c2ecf20Sopenharmony_ci	period_nsec = perout_request->period.nsec % 1000000000;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	if (period_sec == 0) {
5448c2ecf20Sopenharmony_ci		if (period_nsec >= 400000000) {
5458c2ecf20Sopenharmony_ci			pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_;
5468c2ecf20Sopenharmony_ci		} else if (period_nsec >= 20000000) {
5478c2ecf20Sopenharmony_ci			pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10MS_;
5488c2ecf20Sopenharmony_ci		} else if (period_nsec >= 2000000) {
5498c2ecf20Sopenharmony_ci			pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_1MS_;
5508c2ecf20Sopenharmony_ci		} else if (period_nsec >= 200000) {
5518c2ecf20Sopenharmony_ci			pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_;
5528c2ecf20Sopenharmony_ci		} else if (period_nsec >= 20000) {
5538c2ecf20Sopenharmony_ci			pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10US_;
5548c2ecf20Sopenharmony_ci		} else if (period_nsec >= 200) {
5558c2ecf20Sopenharmony_ci			pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100NS_;
5568c2ecf20Sopenharmony_ci		} else {
5578c2ecf20Sopenharmony_ci			netif_warn(adapter, drv, adapter->netdev,
5588c2ecf20Sopenharmony_ci				   "perout period too small, minimum is 200nS\n");
5598c2ecf20Sopenharmony_ci			goto failed;
5608c2ecf20Sopenharmony_ci		}
5618c2ecf20Sopenharmony_ci	} else {
5628c2ecf20Sopenharmony_ci		pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_;
5638c2ecf20Sopenharmony_ci	}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	/* turn off by setting target far in future */
5668c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter,
5678c2ecf20Sopenharmony_ci			  PTP_CLOCK_TARGET_SEC_X(perout->event_ch),
5688c2ecf20Sopenharmony_ci			  0xFFFF0000);
5698c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter,
5708c2ecf20Sopenharmony_ci			  PTP_CLOCK_TARGET_NS_X(perout->event_ch), 0);
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	/* Configure to pulse every period */
5738c2ecf20Sopenharmony_ci	general_config = lan743x_csr_read(adapter, PTP_GENERAL_CONFIG);
5748c2ecf20Sopenharmony_ci	general_config &= ~(PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_
5758c2ecf20Sopenharmony_ci			  (perout->event_ch));
5768c2ecf20Sopenharmony_ci	general_config |= PTP_GENERAL_CONFIG_CLOCK_EVENT_X_SET_
5778c2ecf20Sopenharmony_ci			  (perout->event_ch, pulse_width);
5788c2ecf20Sopenharmony_ci	general_config &= ~PTP_GENERAL_CONFIG_RELOAD_ADD_X_
5798c2ecf20Sopenharmony_ci			  (perout->event_ch);
5808c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, PTP_GENERAL_CONFIG, general_config);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	/* set the reload to one toggle cycle */
5838c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter,
5848c2ecf20Sopenharmony_ci			  PTP_CLOCK_TARGET_RELOAD_SEC_X(perout->event_ch),
5858c2ecf20Sopenharmony_ci			  period_sec);
5868c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter,
5878c2ecf20Sopenharmony_ci			  PTP_CLOCK_TARGET_RELOAD_NS_X(perout->event_ch),
5888c2ecf20Sopenharmony_ci			  period_nsec);
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	/* set the start time */
5918c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter,
5928c2ecf20Sopenharmony_ci			  PTP_CLOCK_TARGET_SEC_X(perout->event_ch),
5938c2ecf20Sopenharmony_ci			  start_sec);
5948c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter,
5958c2ecf20Sopenharmony_ci			  PTP_CLOCK_TARGET_NS_X(perout->event_ch),
5968c2ecf20Sopenharmony_ci			  start_nsec);
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	return 0;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_cifailed:
6018c2ecf20Sopenharmony_ci	lan743x_ptp_perout_off(adapter, index);
6028c2ecf20Sopenharmony_ci	return -ENODEV;
6038c2ecf20Sopenharmony_ci}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_cistatic int lan743x_ptpci_enable(struct ptp_clock_info *ptpci,
6068c2ecf20Sopenharmony_ci				struct ptp_clock_request *request, int on)
6078c2ecf20Sopenharmony_ci{
6088c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp =
6098c2ecf20Sopenharmony_ci		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
6108c2ecf20Sopenharmony_ci	struct lan743x_adapter *adapter =
6118c2ecf20Sopenharmony_ci		container_of(ptp, struct lan743x_adapter, ptp);
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	if (request) {
6148c2ecf20Sopenharmony_ci		switch (request->type) {
6158c2ecf20Sopenharmony_ci		case PTP_CLK_REQ_EXTTS:
6168c2ecf20Sopenharmony_ci			return -EINVAL;
6178c2ecf20Sopenharmony_ci		case PTP_CLK_REQ_PEROUT:
6188c2ecf20Sopenharmony_ci			if (request->perout.index < ptpci->n_per_out)
6198c2ecf20Sopenharmony_ci				return lan743x_ptp_perout(adapter, on,
6208c2ecf20Sopenharmony_ci							  &request->perout);
6218c2ecf20Sopenharmony_ci			return -EINVAL;
6228c2ecf20Sopenharmony_ci		case PTP_CLK_REQ_PPS:
6238c2ecf20Sopenharmony_ci			return -EINVAL;
6248c2ecf20Sopenharmony_ci		default:
6258c2ecf20Sopenharmony_ci			netif_err(adapter, drv, adapter->netdev,
6268c2ecf20Sopenharmony_ci				  "request->type == %d, Unknown\n",
6278c2ecf20Sopenharmony_ci				  request->type);
6288c2ecf20Sopenharmony_ci			break;
6298c2ecf20Sopenharmony_ci		}
6308c2ecf20Sopenharmony_ci	} else {
6318c2ecf20Sopenharmony_ci		netif_err(adapter, drv, adapter->netdev, "request == NULL\n");
6328c2ecf20Sopenharmony_ci	}
6338c2ecf20Sopenharmony_ci	return 0;
6348c2ecf20Sopenharmony_ci}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_cistatic int lan743x_ptpci_verify_pin_config(struct ptp_clock_info *ptp,
6378c2ecf20Sopenharmony_ci					   unsigned int pin,
6388c2ecf20Sopenharmony_ci					   enum ptp_pin_function func,
6398c2ecf20Sopenharmony_ci					   unsigned int chan)
6408c2ecf20Sopenharmony_ci{
6418c2ecf20Sopenharmony_ci	int result = 0;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	/* Confirm the requested function is supported. Parameter
6448c2ecf20Sopenharmony_ci	 * validation is done by the caller.
6458c2ecf20Sopenharmony_ci	 */
6468c2ecf20Sopenharmony_ci	switch (func) {
6478c2ecf20Sopenharmony_ci	case PTP_PF_NONE:
6488c2ecf20Sopenharmony_ci	case PTP_PF_PEROUT:
6498c2ecf20Sopenharmony_ci		break;
6508c2ecf20Sopenharmony_ci	case PTP_PF_EXTTS:
6518c2ecf20Sopenharmony_ci	case PTP_PF_PHYSYNC:
6528c2ecf20Sopenharmony_ci	default:
6538c2ecf20Sopenharmony_ci		result = -1;
6548c2ecf20Sopenharmony_ci		break;
6558c2ecf20Sopenharmony_ci	}
6568c2ecf20Sopenharmony_ci	return result;
6578c2ecf20Sopenharmony_ci}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_cistatic long lan743x_ptpci_do_aux_work(struct ptp_clock_info *ptpci)
6608c2ecf20Sopenharmony_ci{
6618c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp =
6628c2ecf20Sopenharmony_ci		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
6638c2ecf20Sopenharmony_ci	struct lan743x_adapter *adapter =
6648c2ecf20Sopenharmony_ci		container_of(ptp, struct lan743x_adapter, ptp);
6658c2ecf20Sopenharmony_ci	u32 cap_info, cause, header, nsec, seconds;
6668c2ecf20Sopenharmony_ci	bool new_timestamp_available = false;
6678c2ecf20Sopenharmony_ci	int count = 0;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	while ((count < 100) &&
6708c2ecf20Sopenharmony_ci	       (lan743x_csr_read(adapter, PTP_INT_STS) & PTP_INT_BIT_TX_TS_)) {
6718c2ecf20Sopenharmony_ci		count++;
6728c2ecf20Sopenharmony_ci		cap_info = lan743x_csr_read(adapter, PTP_CAP_INFO);
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci		if (PTP_CAP_INFO_TX_TS_CNT_GET_(cap_info) > 0) {
6758c2ecf20Sopenharmony_ci			seconds = lan743x_csr_read(adapter,
6768c2ecf20Sopenharmony_ci						   PTP_TX_EGRESS_SEC);
6778c2ecf20Sopenharmony_ci			nsec = lan743x_csr_read(adapter, PTP_TX_EGRESS_NS);
6788c2ecf20Sopenharmony_ci			cause = (nsec &
6798c2ecf20Sopenharmony_ci				 PTP_TX_EGRESS_NS_CAPTURE_CAUSE_MASK_);
6808c2ecf20Sopenharmony_ci			header = lan743x_csr_read(adapter,
6818c2ecf20Sopenharmony_ci						  PTP_TX_MSG_HEADER);
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci			if (cause == PTP_TX_EGRESS_NS_CAPTURE_CAUSE_SW_) {
6848c2ecf20Sopenharmony_ci				nsec &= PTP_TX_EGRESS_NS_TS_NS_MASK_;
6858c2ecf20Sopenharmony_ci				lan743x_ptp_tx_ts_enqueue_ts(adapter,
6868c2ecf20Sopenharmony_ci							     seconds, nsec,
6878c2ecf20Sopenharmony_ci							     header);
6888c2ecf20Sopenharmony_ci				new_timestamp_available = true;
6898c2ecf20Sopenharmony_ci			} else if (cause ==
6908c2ecf20Sopenharmony_ci				PTP_TX_EGRESS_NS_CAPTURE_CAUSE_AUTO_) {
6918c2ecf20Sopenharmony_ci				netif_err(adapter, drv, adapter->netdev,
6928c2ecf20Sopenharmony_ci					  "Auto capture cause not supported\n");
6938c2ecf20Sopenharmony_ci			} else {
6948c2ecf20Sopenharmony_ci				netif_warn(adapter, drv, adapter->netdev,
6958c2ecf20Sopenharmony_ci					   "unknown tx timestamp capture cause\n");
6968c2ecf20Sopenharmony_ci			}
6978c2ecf20Sopenharmony_ci		} else {
6988c2ecf20Sopenharmony_ci			netif_warn(adapter, drv, adapter->netdev,
6998c2ecf20Sopenharmony_ci				   "TX TS INT but no TX TS CNT\n");
7008c2ecf20Sopenharmony_ci		}
7018c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter, PTP_INT_STS, PTP_INT_BIT_TX_TS_);
7028c2ecf20Sopenharmony_ci	}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	if (new_timestamp_available)
7058c2ecf20Sopenharmony_ci		lan743x_ptp_tx_ts_complete(adapter);
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_);
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	return -1;
7108c2ecf20Sopenharmony_ci}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_cistatic void lan743x_ptp_clock_get(struct lan743x_adapter *adapter,
7138c2ecf20Sopenharmony_ci				  u32 *seconds, u32 *nano_seconds,
7148c2ecf20Sopenharmony_ci				  u32 *sub_nano_seconds)
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = &adapter->ptp;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	mutex_lock(&ptp->command_lock);
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_READ_);
7218c2ecf20Sopenharmony_ci	lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_CLOCK_READ_);
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	if (seconds)
7248c2ecf20Sopenharmony_ci		(*seconds) = lan743x_csr_read(adapter, PTP_CLOCK_SEC);
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	if (nano_seconds)
7278c2ecf20Sopenharmony_ci		(*nano_seconds) = lan743x_csr_read(adapter, PTP_CLOCK_NS);
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	if (sub_nano_seconds)
7308c2ecf20Sopenharmony_ci		(*sub_nano_seconds) =
7318c2ecf20Sopenharmony_ci		lan743x_csr_read(adapter, PTP_CLOCK_SUBNS);
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	mutex_unlock(&ptp->command_lock);
7348c2ecf20Sopenharmony_ci}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_cistatic void lan743x_ptp_clock_step(struct lan743x_adapter *adapter,
7378c2ecf20Sopenharmony_ci				   s64 time_step_ns)
7388c2ecf20Sopenharmony_ci{
7398c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = &adapter->ptp;
7408c2ecf20Sopenharmony_ci	u32 nano_seconds_step = 0;
7418c2ecf20Sopenharmony_ci	u64 abs_time_step_ns = 0;
7428c2ecf20Sopenharmony_ci	u32 unsigned_seconds = 0;
7438c2ecf20Sopenharmony_ci	u32 nano_seconds = 0;
7448c2ecf20Sopenharmony_ci	u32 remainder = 0;
7458c2ecf20Sopenharmony_ci	s32 seconds = 0;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	if (time_step_ns >  15000000000LL) {
7488c2ecf20Sopenharmony_ci		/* convert to clock set */
7498c2ecf20Sopenharmony_ci		lan743x_ptp_clock_get(adapter, &unsigned_seconds,
7508c2ecf20Sopenharmony_ci				      &nano_seconds, NULL);
7518c2ecf20Sopenharmony_ci		unsigned_seconds += div_u64_rem(time_step_ns, 1000000000LL,
7528c2ecf20Sopenharmony_ci						&remainder);
7538c2ecf20Sopenharmony_ci		nano_seconds += remainder;
7548c2ecf20Sopenharmony_ci		if (nano_seconds >= 1000000000) {
7558c2ecf20Sopenharmony_ci			unsigned_seconds++;
7568c2ecf20Sopenharmony_ci			nano_seconds -= 1000000000;
7578c2ecf20Sopenharmony_ci		}
7588c2ecf20Sopenharmony_ci		lan743x_ptp_clock_set(adapter, unsigned_seconds,
7598c2ecf20Sopenharmony_ci				      nano_seconds, 0);
7608c2ecf20Sopenharmony_ci		return;
7618c2ecf20Sopenharmony_ci	} else if (time_step_ns < -15000000000LL) {
7628c2ecf20Sopenharmony_ci		/* convert to clock set */
7638c2ecf20Sopenharmony_ci		time_step_ns = -time_step_ns;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci		lan743x_ptp_clock_get(adapter, &unsigned_seconds,
7668c2ecf20Sopenharmony_ci				      &nano_seconds, NULL);
7678c2ecf20Sopenharmony_ci		unsigned_seconds -= div_u64_rem(time_step_ns, 1000000000LL,
7688c2ecf20Sopenharmony_ci						&remainder);
7698c2ecf20Sopenharmony_ci		nano_seconds_step = remainder;
7708c2ecf20Sopenharmony_ci		if (nano_seconds < nano_seconds_step) {
7718c2ecf20Sopenharmony_ci			unsigned_seconds--;
7728c2ecf20Sopenharmony_ci			nano_seconds += 1000000000;
7738c2ecf20Sopenharmony_ci		}
7748c2ecf20Sopenharmony_ci		nano_seconds -= nano_seconds_step;
7758c2ecf20Sopenharmony_ci		lan743x_ptp_clock_set(adapter, unsigned_seconds,
7768c2ecf20Sopenharmony_ci				      nano_seconds, 0);
7778c2ecf20Sopenharmony_ci		return;
7788c2ecf20Sopenharmony_ci	}
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	/* do clock step */
7818c2ecf20Sopenharmony_ci	if (time_step_ns >= 0) {
7828c2ecf20Sopenharmony_ci		abs_time_step_ns = (u64)(time_step_ns);
7838c2ecf20Sopenharmony_ci		seconds = (s32)div_u64_rem(abs_time_step_ns, 1000000000,
7848c2ecf20Sopenharmony_ci					   &remainder);
7858c2ecf20Sopenharmony_ci		nano_seconds = (u32)remainder;
7868c2ecf20Sopenharmony_ci	} else {
7878c2ecf20Sopenharmony_ci		abs_time_step_ns = (u64)(-time_step_ns);
7888c2ecf20Sopenharmony_ci		seconds = -((s32)div_u64_rem(abs_time_step_ns, 1000000000,
7898c2ecf20Sopenharmony_ci					     &remainder));
7908c2ecf20Sopenharmony_ci		nano_seconds = (u32)remainder;
7918c2ecf20Sopenharmony_ci		if (nano_seconds > 0) {
7928c2ecf20Sopenharmony_ci			/* subtracting nano seconds is not allowed
7938c2ecf20Sopenharmony_ci			 * convert to subtracting from seconds,
7948c2ecf20Sopenharmony_ci			 * and adding to nanoseconds
7958c2ecf20Sopenharmony_ci			 */
7968c2ecf20Sopenharmony_ci			seconds--;
7978c2ecf20Sopenharmony_ci			nano_seconds = (1000000000 - nano_seconds);
7988c2ecf20Sopenharmony_ci		}
7998c2ecf20Sopenharmony_ci	}
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	if (nano_seconds > 0) {
8028c2ecf20Sopenharmony_ci		/* add 8 ns to cover the likely normal increment */
8038c2ecf20Sopenharmony_ci		nano_seconds += 8;
8048c2ecf20Sopenharmony_ci	}
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	if (nano_seconds >= 1000000000) {
8078c2ecf20Sopenharmony_ci		/* carry into seconds */
8088c2ecf20Sopenharmony_ci		seconds++;
8098c2ecf20Sopenharmony_ci		nano_seconds -= 1000000000;
8108c2ecf20Sopenharmony_ci	}
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	while (seconds) {
8138c2ecf20Sopenharmony_ci		mutex_lock(&ptp->command_lock);
8148c2ecf20Sopenharmony_ci		if (seconds > 0) {
8158c2ecf20Sopenharmony_ci			u32 adjustment_value = (u32)seconds;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci			if (adjustment_value > 0xF)
8188c2ecf20Sopenharmony_ci				adjustment_value = 0xF;
8198c2ecf20Sopenharmony_ci			lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ,
8208c2ecf20Sopenharmony_ci					  PTP_CLOCK_STEP_ADJ_DIR_ |
8218c2ecf20Sopenharmony_ci					  adjustment_value);
8228c2ecf20Sopenharmony_ci			seconds -= ((s32)adjustment_value);
8238c2ecf20Sopenharmony_ci		} else {
8248c2ecf20Sopenharmony_ci			u32 adjustment_value = (u32)(-seconds);
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci			if (adjustment_value > 0xF)
8278c2ecf20Sopenharmony_ci				adjustment_value = 0xF;
8288c2ecf20Sopenharmony_ci			lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ,
8298c2ecf20Sopenharmony_ci					  adjustment_value);
8308c2ecf20Sopenharmony_ci			seconds += ((s32)adjustment_value);
8318c2ecf20Sopenharmony_ci		}
8328c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter, PTP_CMD_CTL,
8338c2ecf20Sopenharmony_ci				  PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_);
8348c2ecf20Sopenharmony_ci		lan743x_ptp_wait_till_cmd_done(adapter,
8358c2ecf20Sopenharmony_ci					       PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_);
8368c2ecf20Sopenharmony_ci		mutex_unlock(&ptp->command_lock);
8378c2ecf20Sopenharmony_ci	}
8388c2ecf20Sopenharmony_ci	if (nano_seconds) {
8398c2ecf20Sopenharmony_ci		mutex_lock(&ptp->command_lock);
8408c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ,
8418c2ecf20Sopenharmony_ci				  PTP_CLOCK_STEP_ADJ_DIR_ |
8428c2ecf20Sopenharmony_ci				  (nano_seconds &
8438c2ecf20Sopenharmony_ci				  PTP_CLOCK_STEP_ADJ_VALUE_MASK_));
8448c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter, PTP_CMD_CTL,
8458c2ecf20Sopenharmony_ci				  PTP_CMD_CTL_PTP_CLK_STP_NSEC_);
8468c2ecf20Sopenharmony_ci		lan743x_ptp_wait_till_cmd_done(adapter,
8478c2ecf20Sopenharmony_ci					       PTP_CMD_CTL_PTP_CLK_STP_NSEC_);
8488c2ecf20Sopenharmony_ci		mutex_unlock(&ptp->command_lock);
8498c2ecf20Sopenharmony_ci	}
8508c2ecf20Sopenharmony_ci}
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_civoid lan743x_ptp_isr(void *context)
8538c2ecf20Sopenharmony_ci{
8548c2ecf20Sopenharmony_ci	struct lan743x_adapter *adapter = (struct lan743x_adapter *)context;
8558c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = NULL;
8568c2ecf20Sopenharmony_ci	int enable_flag = 1;
8578c2ecf20Sopenharmony_ci	u32 ptp_int_sts = 0;
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	ptp = &adapter->ptp;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_1588_);
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	ptp_int_sts = lan743x_csr_read(adapter, PTP_INT_STS);
8648c2ecf20Sopenharmony_ci	ptp_int_sts &= lan743x_csr_read(adapter, PTP_INT_EN_SET);
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	if (ptp_int_sts & PTP_INT_BIT_TX_TS_) {
8678c2ecf20Sopenharmony_ci		ptp_schedule_worker(ptp->ptp_clock, 0);
8688c2ecf20Sopenharmony_ci		enable_flag = 0;/* tasklet will re-enable later */
8698c2ecf20Sopenharmony_ci	}
8708c2ecf20Sopenharmony_ci	if (ptp_int_sts & PTP_INT_BIT_TX_SWTS_ERR_) {
8718c2ecf20Sopenharmony_ci		netif_err(adapter, drv, adapter->netdev,
8728c2ecf20Sopenharmony_ci			  "PTP TX Software Timestamp Error\n");
8738c2ecf20Sopenharmony_ci		/* clear int status bit */
8748c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter, PTP_INT_STS,
8758c2ecf20Sopenharmony_ci				  PTP_INT_BIT_TX_SWTS_ERR_);
8768c2ecf20Sopenharmony_ci	}
8778c2ecf20Sopenharmony_ci	if (ptp_int_sts & PTP_INT_BIT_TIMER_B_) {
8788c2ecf20Sopenharmony_ci		/* clear int status bit */
8798c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter, PTP_INT_STS,
8808c2ecf20Sopenharmony_ci				  PTP_INT_BIT_TIMER_B_);
8818c2ecf20Sopenharmony_ci	}
8828c2ecf20Sopenharmony_ci	if (ptp_int_sts & PTP_INT_BIT_TIMER_A_) {
8838c2ecf20Sopenharmony_ci		/* clear int status bit */
8848c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter, PTP_INT_STS,
8858c2ecf20Sopenharmony_ci				  PTP_INT_BIT_TIMER_A_);
8868c2ecf20Sopenharmony_ci	}
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	if (enable_flag) {
8898c2ecf20Sopenharmony_ci		/* re-enable isr */
8908c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_);
8918c2ecf20Sopenharmony_ci	}
8928c2ecf20Sopenharmony_ci}
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_cistatic void lan743x_ptp_tx_ts_enqueue_skb(struct lan743x_adapter *adapter,
8958c2ecf20Sopenharmony_ci					  struct sk_buff *skb, bool ignore_sync)
8968c2ecf20Sopenharmony_ci{
8978c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = &adapter->ptp;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	spin_lock_bh(&ptp->tx_ts_lock);
9008c2ecf20Sopenharmony_ci	if (ptp->tx_ts_skb_queue_size < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) {
9018c2ecf20Sopenharmony_ci		ptp->tx_ts_skb_queue[ptp->tx_ts_skb_queue_size] = skb;
9028c2ecf20Sopenharmony_ci		if (ignore_sync)
9038c2ecf20Sopenharmony_ci			ptp->tx_ts_ignore_sync_queue |=
9048c2ecf20Sopenharmony_ci				BIT(ptp->tx_ts_skb_queue_size);
9058c2ecf20Sopenharmony_ci		ptp->tx_ts_skb_queue_size++;
9068c2ecf20Sopenharmony_ci	} else {
9078c2ecf20Sopenharmony_ci		/* this should never happen, so long as the tx channel
9088c2ecf20Sopenharmony_ci		 * calls and honors the result from
9098c2ecf20Sopenharmony_ci		 * lan743x_ptp_request_tx_timestamp
9108c2ecf20Sopenharmony_ci		 */
9118c2ecf20Sopenharmony_ci		netif_err(adapter, drv, adapter->netdev,
9128c2ecf20Sopenharmony_ci			  "tx ts skb queue overflow\n");
9138c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
9148c2ecf20Sopenharmony_ci	}
9158c2ecf20Sopenharmony_ci	spin_unlock_bh(&ptp->tx_ts_lock);
9168c2ecf20Sopenharmony_ci}
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_cistatic void lan743x_ptp_sync_to_system_clock(struct lan743x_adapter *adapter)
9198c2ecf20Sopenharmony_ci{
9208c2ecf20Sopenharmony_ci	struct timespec64 ts;
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	ktime_get_clocktai_ts64(&ts);
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	lan743x_ptp_clock_set(adapter, ts.tv_sec, ts.tv_nsec, 0);
9258c2ecf20Sopenharmony_ci}
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_civoid lan743x_ptp_update_latency(struct lan743x_adapter *adapter,
9288c2ecf20Sopenharmony_ci				u32 link_speed)
9298c2ecf20Sopenharmony_ci{
9308c2ecf20Sopenharmony_ci	switch (link_speed) {
9318c2ecf20Sopenharmony_ci	case 10:
9328c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter, PTP_LATENCY,
9338c2ecf20Sopenharmony_ci				  PTP_LATENCY_TX_SET_(0) |
9348c2ecf20Sopenharmony_ci				  PTP_LATENCY_RX_SET_(0));
9358c2ecf20Sopenharmony_ci		break;
9368c2ecf20Sopenharmony_ci	case 100:
9378c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter, PTP_LATENCY,
9388c2ecf20Sopenharmony_ci				  PTP_LATENCY_TX_SET_(181) |
9398c2ecf20Sopenharmony_ci				  PTP_LATENCY_RX_SET_(594));
9408c2ecf20Sopenharmony_ci		break;
9418c2ecf20Sopenharmony_ci	case 1000:
9428c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter, PTP_LATENCY,
9438c2ecf20Sopenharmony_ci				  PTP_LATENCY_TX_SET_(30) |
9448c2ecf20Sopenharmony_ci				  PTP_LATENCY_RX_SET_(525));
9458c2ecf20Sopenharmony_ci		break;
9468c2ecf20Sopenharmony_ci	}
9478c2ecf20Sopenharmony_ci}
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ciint lan743x_ptp_init(struct lan743x_adapter *adapter)
9508c2ecf20Sopenharmony_ci{
9518c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = &adapter->ptp;
9528c2ecf20Sopenharmony_ci	int i;
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	mutex_init(&ptp->command_lock);
9558c2ecf20Sopenharmony_ci	spin_lock_init(&ptp->tx_ts_lock);
9568c2ecf20Sopenharmony_ci	ptp->used_event_ch = 0;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	for (i = 0; i < LAN743X_PTP_N_EVENT_CHAN; i++) {
9598c2ecf20Sopenharmony_ci		ptp->perout[i].event_ch = -1;
9608c2ecf20Sopenharmony_ci		ptp->perout[i].gpio_pin = -1;
9618c2ecf20Sopenharmony_ci	}
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	lan743x_led_mux_save(adapter);
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	return 0;
9668c2ecf20Sopenharmony_ci}
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ciint lan743x_ptp_open(struct lan743x_adapter *adapter)
9698c2ecf20Sopenharmony_ci{
9708c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = &adapter->ptp;
9718c2ecf20Sopenharmony_ci	int ret = -ENODEV;
9728c2ecf20Sopenharmony_ci	u32 temp;
9738c2ecf20Sopenharmony_ci	int i;
9748c2ecf20Sopenharmony_ci	int n_pins;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	lan743x_ptp_reset(adapter);
9778c2ecf20Sopenharmony_ci	lan743x_ptp_sync_to_system_clock(adapter);
9788c2ecf20Sopenharmony_ci	temp = lan743x_csr_read(adapter, PTP_TX_MOD2);
9798c2ecf20Sopenharmony_ci	temp |= PTP_TX_MOD2_TX_PTP_CLR_UDPV4_CHKSUM_;
9808c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, PTP_TX_MOD2, temp);
9818c2ecf20Sopenharmony_ci	lan743x_ptp_enable(adapter);
9828c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_);
9838c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, PTP_INT_EN_SET,
9848c2ecf20Sopenharmony_ci			  PTP_INT_BIT_TX_SWTS_ERR_ | PTP_INT_BIT_TX_TS_);
9858c2ecf20Sopenharmony_ci	ptp->flags |= PTP_FLAG_ISR_ENABLED;
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	if (!IS_ENABLED(CONFIG_PTP_1588_CLOCK))
9888c2ecf20Sopenharmony_ci		return 0;
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	switch (adapter->csr.id_rev & ID_REV_ID_MASK_) {
9918c2ecf20Sopenharmony_ci	case ID_REV_ID_LAN7430_:
9928c2ecf20Sopenharmony_ci		n_pins = LAN7430_N_GPIO;
9938c2ecf20Sopenharmony_ci		break;
9948c2ecf20Sopenharmony_ci	case ID_REV_ID_LAN7431_:
9958c2ecf20Sopenharmony_ci		n_pins = LAN7431_N_GPIO;
9968c2ecf20Sopenharmony_ci		break;
9978c2ecf20Sopenharmony_ci	default:
9988c2ecf20Sopenharmony_ci		netif_warn(adapter, drv, adapter->netdev,
9998c2ecf20Sopenharmony_ci			   "Unknown LAN743x (%08x). Assuming no GPIO\n",
10008c2ecf20Sopenharmony_ci			   adapter->csr.id_rev);
10018c2ecf20Sopenharmony_ci		n_pins = 0;
10028c2ecf20Sopenharmony_ci		break;
10038c2ecf20Sopenharmony_ci	}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	if (n_pins > LAN743X_PTP_N_GPIO)
10068c2ecf20Sopenharmony_ci		n_pins = LAN743X_PTP_N_GPIO;
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	for (i = 0; i < n_pins; i++) {
10098c2ecf20Sopenharmony_ci		struct ptp_pin_desc *ptp_pin = &ptp->pin_config[i];
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci		snprintf(ptp_pin->name,
10128c2ecf20Sopenharmony_ci			 sizeof(ptp_pin->name), "lan743x_ptp_pin_%02d", i);
10138c2ecf20Sopenharmony_ci		ptp_pin->index = i;
10148c2ecf20Sopenharmony_ci		ptp_pin->func = PTP_PF_NONE;
10158c2ecf20Sopenharmony_ci	}
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	ptp->ptp_clock_info.owner = THIS_MODULE;
10188c2ecf20Sopenharmony_ci	snprintf(ptp->ptp_clock_info.name, 16, "%pm",
10198c2ecf20Sopenharmony_ci		 adapter->netdev->dev_addr);
10208c2ecf20Sopenharmony_ci	ptp->ptp_clock_info.max_adj = LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB;
10218c2ecf20Sopenharmony_ci	ptp->ptp_clock_info.n_alarm = 0;
10228c2ecf20Sopenharmony_ci	ptp->ptp_clock_info.n_ext_ts = 0;
10238c2ecf20Sopenharmony_ci	ptp->ptp_clock_info.n_per_out = LAN743X_PTP_N_EVENT_CHAN;
10248c2ecf20Sopenharmony_ci	ptp->ptp_clock_info.n_pins = n_pins;
10258c2ecf20Sopenharmony_ci	ptp->ptp_clock_info.pps = 0;
10268c2ecf20Sopenharmony_ci	ptp->ptp_clock_info.pin_config = ptp->pin_config;
10278c2ecf20Sopenharmony_ci	ptp->ptp_clock_info.adjfine = lan743x_ptpci_adjfine;
10288c2ecf20Sopenharmony_ci	ptp->ptp_clock_info.adjfreq = lan743x_ptpci_adjfreq;
10298c2ecf20Sopenharmony_ci	ptp->ptp_clock_info.adjtime = lan743x_ptpci_adjtime;
10308c2ecf20Sopenharmony_ci	ptp->ptp_clock_info.gettime64 = lan743x_ptpci_gettime64;
10318c2ecf20Sopenharmony_ci	ptp->ptp_clock_info.getcrosststamp = NULL;
10328c2ecf20Sopenharmony_ci	ptp->ptp_clock_info.settime64 = lan743x_ptpci_settime64;
10338c2ecf20Sopenharmony_ci	ptp->ptp_clock_info.enable = lan743x_ptpci_enable;
10348c2ecf20Sopenharmony_ci	ptp->ptp_clock_info.do_aux_work = lan743x_ptpci_do_aux_work;
10358c2ecf20Sopenharmony_ci	ptp->ptp_clock_info.verify = lan743x_ptpci_verify_pin_config;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	ptp->ptp_clock = ptp_clock_register(&ptp->ptp_clock_info,
10388c2ecf20Sopenharmony_ci					    &adapter->pdev->dev);
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	if (IS_ERR(ptp->ptp_clock)) {
10418c2ecf20Sopenharmony_ci		netif_err(adapter, ifup, adapter->netdev,
10428c2ecf20Sopenharmony_ci			  "ptp_clock_register failed\n");
10438c2ecf20Sopenharmony_ci		goto done;
10448c2ecf20Sopenharmony_ci	}
10458c2ecf20Sopenharmony_ci	ptp->flags |= PTP_FLAG_PTP_CLOCK_REGISTERED;
10468c2ecf20Sopenharmony_ci	netif_info(adapter, ifup, adapter->netdev,
10478c2ecf20Sopenharmony_ci		   "successfully registered ptp clock\n");
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	return 0;
10508c2ecf20Sopenharmony_cidone:
10518c2ecf20Sopenharmony_ci	lan743x_ptp_close(adapter);
10528c2ecf20Sopenharmony_ci	return ret;
10538c2ecf20Sopenharmony_ci}
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_civoid lan743x_ptp_close(struct lan743x_adapter *adapter)
10568c2ecf20Sopenharmony_ci{
10578c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = &adapter->ptp;
10588c2ecf20Sopenharmony_ci	int index;
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_PTP_1588_CLOCK) &&
10618c2ecf20Sopenharmony_ci	    (ptp->flags & PTP_FLAG_PTP_CLOCK_REGISTERED)) {
10628c2ecf20Sopenharmony_ci		ptp_clock_unregister(ptp->ptp_clock);
10638c2ecf20Sopenharmony_ci		ptp->ptp_clock = NULL;
10648c2ecf20Sopenharmony_ci		ptp->flags &= ~PTP_FLAG_PTP_CLOCK_REGISTERED;
10658c2ecf20Sopenharmony_ci		netif_info(adapter, drv, adapter->netdev,
10668c2ecf20Sopenharmony_ci			   "ptp clock unregister\n");
10678c2ecf20Sopenharmony_ci	}
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	if (ptp->flags & PTP_FLAG_ISR_ENABLED) {
10708c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter, PTP_INT_EN_CLR,
10718c2ecf20Sopenharmony_ci				  PTP_INT_BIT_TX_SWTS_ERR_ |
10728c2ecf20Sopenharmony_ci				  PTP_INT_BIT_TX_TS_);
10738c2ecf20Sopenharmony_ci		lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_1588_);
10748c2ecf20Sopenharmony_ci		ptp->flags &= ~PTP_FLAG_ISR_ENABLED;
10758c2ecf20Sopenharmony_ci	}
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	/* clean up pending timestamp requests */
10788c2ecf20Sopenharmony_ci	lan743x_ptp_tx_ts_complete(adapter);
10798c2ecf20Sopenharmony_ci	spin_lock_bh(&ptp->tx_ts_lock);
10808c2ecf20Sopenharmony_ci	for (index = 0;
10818c2ecf20Sopenharmony_ci		index < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS;
10828c2ecf20Sopenharmony_ci		index++) {
10838c2ecf20Sopenharmony_ci		struct sk_buff *skb = ptp->tx_ts_skb_queue[index];
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
10868c2ecf20Sopenharmony_ci		ptp->tx_ts_skb_queue[index] = NULL;
10878c2ecf20Sopenharmony_ci		ptp->tx_ts_seconds_queue[index] = 0;
10888c2ecf20Sopenharmony_ci		ptp->tx_ts_nseconds_queue[index] = 0;
10898c2ecf20Sopenharmony_ci	}
10908c2ecf20Sopenharmony_ci	ptp->tx_ts_skb_queue_size = 0;
10918c2ecf20Sopenharmony_ci	ptp->tx_ts_queue_size = 0;
10928c2ecf20Sopenharmony_ci	ptp->pending_tx_timestamps = 0;
10938c2ecf20Sopenharmony_ci	spin_unlock_bh(&ptp->tx_ts_lock);
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	lan743x_led_mux_restore(adapter);
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	lan743x_ptp_disable(adapter);
10988c2ecf20Sopenharmony_ci}
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_cistatic void lan743x_ptp_set_sync_ts_insert(struct lan743x_adapter *adapter,
11018c2ecf20Sopenharmony_ci					   bool ts_insert_enable)
11028c2ecf20Sopenharmony_ci{
11038c2ecf20Sopenharmony_ci	u32 ptp_tx_mod = lan743x_csr_read(adapter, PTP_TX_MOD);
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	if (ts_insert_enable)
11068c2ecf20Sopenharmony_ci		ptp_tx_mod |= PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_;
11078c2ecf20Sopenharmony_ci	else
11088c2ecf20Sopenharmony_ci		ptp_tx_mod &= ~PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_;
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, PTP_TX_MOD, ptp_tx_mod);
11118c2ecf20Sopenharmony_ci}
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_cistatic bool lan743x_ptp_is_enabled(struct lan743x_adapter *adapter)
11148c2ecf20Sopenharmony_ci{
11158c2ecf20Sopenharmony_ci	if (lan743x_csr_read(adapter, PTP_CMD_CTL) & PTP_CMD_CTL_PTP_ENABLE_)
11168c2ecf20Sopenharmony_ci		return true;
11178c2ecf20Sopenharmony_ci	return false;
11188c2ecf20Sopenharmony_ci}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_cistatic void lan743x_ptp_enable(struct lan743x_adapter *adapter)
11218c2ecf20Sopenharmony_ci{
11228c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = &adapter->ptp;
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	mutex_lock(&ptp->command_lock);
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	if (lan743x_ptp_is_enabled(adapter)) {
11278c2ecf20Sopenharmony_ci		netif_warn(adapter, drv, adapter->netdev,
11288c2ecf20Sopenharmony_ci			   "PTP already enabled\n");
11298c2ecf20Sopenharmony_ci		goto done;
11308c2ecf20Sopenharmony_ci	}
11318c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_ENABLE_);
11328c2ecf20Sopenharmony_cidone:
11338c2ecf20Sopenharmony_ci	mutex_unlock(&ptp->command_lock);
11348c2ecf20Sopenharmony_ci}
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_cistatic void lan743x_ptp_disable(struct lan743x_adapter *adapter)
11378c2ecf20Sopenharmony_ci{
11388c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = &adapter->ptp;
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	mutex_lock(&ptp->command_lock);
11418c2ecf20Sopenharmony_ci	if (!lan743x_ptp_is_enabled(adapter)) {
11428c2ecf20Sopenharmony_ci		netif_warn(adapter, drv, adapter->netdev,
11438c2ecf20Sopenharmony_ci			   "PTP already disabled\n");
11448c2ecf20Sopenharmony_ci		goto done;
11458c2ecf20Sopenharmony_ci	}
11468c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_DISABLE_);
11478c2ecf20Sopenharmony_ci	lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_ENABLE_);
11488c2ecf20Sopenharmony_cidone:
11498c2ecf20Sopenharmony_ci	mutex_unlock(&ptp->command_lock);
11508c2ecf20Sopenharmony_ci}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_cistatic void lan743x_ptp_reset(struct lan743x_adapter *adapter)
11538c2ecf20Sopenharmony_ci{
11548c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = &adapter->ptp;
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci	mutex_lock(&ptp->command_lock);
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci	if (lan743x_ptp_is_enabled(adapter)) {
11598c2ecf20Sopenharmony_ci		netif_err(adapter, drv, adapter->netdev,
11608c2ecf20Sopenharmony_ci			  "Attempting reset while enabled\n");
11618c2ecf20Sopenharmony_ci		goto done;
11628c2ecf20Sopenharmony_ci	}
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_RESET_);
11658c2ecf20Sopenharmony_ci	lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_RESET_);
11668c2ecf20Sopenharmony_cidone:
11678c2ecf20Sopenharmony_ci	mutex_unlock(&ptp->command_lock);
11688c2ecf20Sopenharmony_ci}
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_cistatic void lan743x_ptp_clock_set(struct lan743x_adapter *adapter,
11718c2ecf20Sopenharmony_ci				  u32 seconds, u32 nano_seconds,
11728c2ecf20Sopenharmony_ci				  u32 sub_nano_seconds)
11738c2ecf20Sopenharmony_ci{
11748c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = &adapter->ptp;
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	mutex_lock(&ptp->command_lock);
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, PTP_CLOCK_SEC, seconds);
11798c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, PTP_CLOCK_NS, nano_seconds);
11808c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, PTP_CLOCK_SUBNS, sub_nano_seconds);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_LOAD_);
11838c2ecf20Sopenharmony_ci	lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_CLOCK_LOAD_);
11848c2ecf20Sopenharmony_ci	mutex_unlock(&ptp->command_lock);
11858c2ecf20Sopenharmony_ci}
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_cibool lan743x_ptp_request_tx_timestamp(struct lan743x_adapter *adapter)
11888c2ecf20Sopenharmony_ci{
11898c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = &adapter->ptp;
11908c2ecf20Sopenharmony_ci	bool result = false;
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci	spin_lock_bh(&ptp->tx_ts_lock);
11938c2ecf20Sopenharmony_ci	if (ptp->pending_tx_timestamps < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) {
11948c2ecf20Sopenharmony_ci		/* request granted */
11958c2ecf20Sopenharmony_ci		ptp->pending_tx_timestamps++;
11968c2ecf20Sopenharmony_ci		result = true;
11978c2ecf20Sopenharmony_ci	}
11988c2ecf20Sopenharmony_ci	spin_unlock_bh(&ptp->tx_ts_lock);
11998c2ecf20Sopenharmony_ci	return result;
12008c2ecf20Sopenharmony_ci}
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_civoid lan743x_ptp_unrequest_tx_timestamp(struct lan743x_adapter *adapter)
12038c2ecf20Sopenharmony_ci{
12048c2ecf20Sopenharmony_ci	struct lan743x_ptp *ptp = &adapter->ptp;
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	spin_lock_bh(&ptp->tx_ts_lock);
12078c2ecf20Sopenharmony_ci	if (ptp->pending_tx_timestamps > 0)
12088c2ecf20Sopenharmony_ci		ptp->pending_tx_timestamps--;
12098c2ecf20Sopenharmony_ci	else
12108c2ecf20Sopenharmony_ci		netif_err(adapter, drv, adapter->netdev,
12118c2ecf20Sopenharmony_ci			  "unrequest failed, pending_tx_timestamps==0\n");
12128c2ecf20Sopenharmony_ci	spin_unlock_bh(&ptp->tx_ts_lock);
12138c2ecf20Sopenharmony_ci}
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_civoid lan743x_ptp_tx_timestamp_skb(struct lan743x_adapter *adapter,
12168c2ecf20Sopenharmony_ci				  struct sk_buff *skb, bool ignore_sync)
12178c2ecf20Sopenharmony_ci{
12188c2ecf20Sopenharmony_ci	lan743x_ptp_tx_ts_enqueue_skb(adapter, skb, ignore_sync);
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci	lan743x_ptp_tx_ts_complete(adapter);
12218c2ecf20Sopenharmony_ci}
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ciint lan743x_ptp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
12248c2ecf20Sopenharmony_ci{
12258c2ecf20Sopenharmony_ci	struct lan743x_adapter *adapter = netdev_priv(netdev);
12268c2ecf20Sopenharmony_ci	struct hwtstamp_config config;
12278c2ecf20Sopenharmony_ci	int ret = 0;
12288c2ecf20Sopenharmony_ci	int index;
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	if (!ifr) {
12318c2ecf20Sopenharmony_ci		netif_err(adapter, drv, adapter->netdev,
12328c2ecf20Sopenharmony_ci			  "SIOCSHWTSTAMP, ifr == NULL\n");
12338c2ecf20Sopenharmony_ci		return -EINVAL;
12348c2ecf20Sopenharmony_ci	}
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
12378c2ecf20Sopenharmony_ci		return -EFAULT;
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	if (config.flags) {
12408c2ecf20Sopenharmony_ci		netif_warn(adapter, drv, adapter->netdev,
12418c2ecf20Sopenharmony_ci			   "ignoring hwtstamp_config.flags == 0x%08X, expected 0\n",
12428c2ecf20Sopenharmony_ci			   config.flags);
12438c2ecf20Sopenharmony_ci	}
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	switch (config.tx_type) {
12468c2ecf20Sopenharmony_ci	case HWTSTAMP_TX_OFF:
12478c2ecf20Sopenharmony_ci		for (index = 0; index < LAN743X_MAX_TX_CHANNELS;
12488c2ecf20Sopenharmony_ci			index++)
12498c2ecf20Sopenharmony_ci			lan743x_tx_set_timestamping_mode(&adapter->tx[index],
12508c2ecf20Sopenharmony_ci							 false, false);
12518c2ecf20Sopenharmony_ci		lan743x_ptp_set_sync_ts_insert(adapter, false);
12528c2ecf20Sopenharmony_ci		break;
12538c2ecf20Sopenharmony_ci	case HWTSTAMP_TX_ON:
12548c2ecf20Sopenharmony_ci		for (index = 0; index < LAN743X_MAX_TX_CHANNELS;
12558c2ecf20Sopenharmony_ci			index++)
12568c2ecf20Sopenharmony_ci			lan743x_tx_set_timestamping_mode(&adapter->tx[index],
12578c2ecf20Sopenharmony_ci							 true, false);
12588c2ecf20Sopenharmony_ci		lan743x_ptp_set_sync_ts_insert(adapter, false);
12598c2ecf20Sopenharmony_ci		break;
12608c2ecf20Sopenharmony_ci	case HWTSTAMP_TX_ONESTEP_SYNC:
12618c2ecf20Sopenharmony_ci		for (index = 0; index < LAN743X_MAX_TX_CHANNELS;
12628c2ecf20Sopenharmony_ci			index++)
12638c2ecf20Sopenharmony_ci			lan743x_tx_set_timestamping_mode(&adapter->tx[index],
12648c2ecf20Sopenharmony_ci							 true, true);
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci		lan743x_ptp_set_sync_ts_insert(adapter, true);
12678c2ecf20Sopenharmony_ci		break;
12688c2ecf20Sopenharmony_ci	case HWTSTAMP_TX_ONESTEP_P2P:
12698c2ecf20Sopenharmony_ci		ret = -ERANGE;
12708c2ecf20Sopenharmony_ci		break;
12718c2ecf20Sopenharmony_ci	default:
12728c2ecf20Sopenharmony_ci		netif_warn(adapter, drv, adapter->netdev,
12738c2ecf20Sopenharmony_ci			   "  tx_type = %d, UNKNOWN\n", config.tx_type);
12748c2ecf20Sopenharmony_ci		ret = -EINVAL;
12758c2ecf20Sopenharmony_ci		break;
12768c2ecf20Sopenharmony_ci	}
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	if (!ret)
12798c2ecf20Sopenharmony_ci		return copy_to_user(ifr->ifr_data, &config,
12808c2ecf20Sopenharmony_ci			sizeof(config)) ? -EFAULT : 0;
12818c2ecf20Sopenharmony_ci	return ret;
12828c2ecf20Sopenharmony_ci}
1283