lkml.org 
[lkml]   [2010]   [Aug]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[MeeGo-Dev][PATCH] Topcliff: Update PCH_IEEE1588 driver to 2.6.35
IEEE1588 driver of Topcliff PCH

Topcliff PCH is the platform controller hub that is going to be used in
Intel's upcoming general embedded platform. All IO peripherals in
Topcliff PCH are actually devices sitting on AMBA bus.
Topcliff PCH has IEEE1588 I/F. This driver enables IEEE1588 function on CAN or
Ethernet communications.

Signed-off-by: Masayuki Ohtake <masa-korg@dsn.okisemi.com>
---
drivers/char/Kconfig | 9 +
drivers/char/Makefile | 2 +
drivers/char/pch_ieee1588/Makefile | 1 +
drivers/char/pch_ieee1588/pch_ieee1588.c | 3947 ++++++++++++++++++++++++++++++
drivers/char/pch_ieee1588/pch_ieee1588.h | 528 ++++
5 files changed, 4487 insertions(+), 0 deletions(-)
create mode 100755 drivers/char/pch_ieee1588/Makefile
create mode 100644 drivers/char/pch_ieee1588/pch_ieee1588.c
create mode 100644 drivers/char/pch_ieee1588/pch_ieee1588.h

diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 7cfcc62..4784971 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -4,6 +4,15 @@

menu "Character devices"

+config PCH_IEEE1588
+ tristate "PCH IEEE1588 of Intel Topcliff"
+ depends on PCI
+ help
+ This driver is for PCH IEEE1588 of Topcliff which is an IOH for x86
+ embedded processor.
+ This driver enables IEEE1588 function on CAN or Ethernet
+ communications.
+
config VT
bool "Virtual terminal" if EMBEDDED
depends on !S390
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 88d6eac..81fb2d0 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -113,6 +113,8 @@ obj-$(CONFIG_RAMOOPS) += ramoops.o
obj-$(CONFIG_JS_RTC) += js-rtc.o
js-rtc-y = rtc.o

+obj-$(CONFIG_PCH_IEEE1588) += pch_ieee1588/
+
# Files generated that shall be removed upon make clean
clean-files := consolemap_deftbl.c defkeymap.c

diff --git a/drivers/char/pch_ieee1588/Makefile b/drivers/char/pch_ieee1588/Makefile
new file mode 100755
index 0000000..e5199ac
--- /dev/null
+++ b/drivers/char/pch_ieee1588/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_PCH_IEEE1588) += pch_ieee1588.o
diff --git a/drivers/char/pch_ieee1588/pch_ieee1588.c b/drivers/char/pch_ieee1588/pch_ieee1588.c
new file mode 100644
index 0000000..ad51c41
--- /dev/null
+++ b/drivers/char/pch_ieee1588/pch_ieee1588.c
@@ -0,0 +1,3947 @@
+/*
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <linux/cdev.h>
+#include <linux/pci.h>
+#include <linux/ioctl.h>
+#include <linux/sched.h>
+
+#include "pch_ieee1588.h"
+
+static struct pch_tim_val pch_target_time; /* This variable is updated
+ from the target time
+ reached callback */
+
+static struct pch_auxtimeioctl pch_aux_time; /* This variable is updated
+ from the Auxiliary
+ master/slave time
+ captured callback */
+
+
+static u32 pch_pps_time; /* This variable is updated from the Pulse per
+ second match callback */
+
+#define PCH_IOC_TBL_ENTRIES \
+ (sizeof pch_ioc_tbl_data / sizeof pch_ioc_tbl_data[0])
+
+static void (*pch_tt_cbptr) (struct pch_tim_val tgt_time,
+ struct pch_dev *pch_pdata);
+static void (*pch_am_cbptr) (enum pch_auxmode aux_mode,
+ struct pch_tim_val aux_time, struct pch_dev *pch_pdata);
+static void (*pch_as_cbptr) (enum pch_auxmode aux_mode,
+ struct pch_tim_val aux_time, struct pch_dev *pch_pdata);
+
+static void (*pch_pps_cbptr) (u32 pps, struct pch_dev *pch_pdata);
+
+static struct pch_stats pch_stats = { 0, 0 }; /* The transmit and
+ receive timestamp
+ statistics */
+
+static struct pch_regs_set pch_regs; /* To save the state of all
+ registers of the module */
+
+/* structure to hold the module parameters */
+static struct pch_params_ pch_param = {
+ 1, 0, 0, "00:00:00:00:00:00"
+};
+
+static DEFINE_MUTEX(pch_1588_mutex);
+
+static inline void pch_pps_imask_set(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+
+ /* Enable PPS Interrupt */
+ PCH_SET_ADDR_BIT(p + PCH_TSC_OFFSET, PCH_TSC_PPSM_MASK);
+}
+
+static inline void pch_amms_imask_set(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Enable Auxiliary Master Mode Snapshot Interrupt */
+ PCH_SET_ADDR_BIT(p + PCH_TSC_OFFSET, PCH_TSC_AMMS_MASK);
+}
+
+static inline void pch_asms_imask_set(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Enable Auxiliary Slave Mode Snapshot Interrupt */
+ PCH_SET_ADDR_BIT(p + PCH_TSC_OFFSET, PCH_TSC_ASMS_MASK);
+}
+
+static inline void pch_ttm_imask_set(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Enable Target Time Interrupt */
+ PCH_SET_ADDR_BIT(p + PCH_TSC_OFFSET, PCH_TSC_TTM_MASK);
+}
+
+static inline u32 pch_pps_imask_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get PPS Interrupt Mask value */
+ return PCH_BIT_SET_CHECK(p + PCH_TSC_OFFSET, PCH_TSC_PPSM_MASK);
+}
+
+static inline u32 pch_amms_imask_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get Auxiliary Master Mode Snapshot Interrupt Mask value */
+ return PCH_BIT_SET_CHECK(p + PCH_TSC_OFFSET, PCH_TSC_AMMS_MASK);
+}
+
+static inline u32 pch_asms_imask_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get Auxiliary Slave Mode Snapshot Interrupt Mask value */
+ return PCH_BIT_SET_CHECK(p + PCH_TSC_OFFSET, PCH_TSC_ASMS_MASK);
+}
+
+static inline u32 pch_ttm_imask_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get Target Time Interrupt Mask value */
+ return PCH_BIT_SET_CHECK(p + PCH_TSC_OFFSET, PCH_TSC_TTM_MASK);
+}
+
+static inline void pch_pps_imask_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Disable PPS Interrupt */
+ PCH_CLR_ADDR_BIT(p + PCH_TSC_OFFSET, PCH_TSC_PPSM_MASK);
+}
+
+static inline void pch_amms_imask_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Disable Auxiliary Master Mode Snapshot Interrupt. */
+ PCH_CLR_ADDR_BIT(p + PCH_TSC_OFFSET, PCH_TSC_AMMS_MASK);
+}
+
+static inline void pch_asms_imask_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Disable Auxiliary Slave Mode Snapshot Interrupt */
+ PCH_CLR_ADDR_BIT(p + PCH_TSC_OFFSET, PCH_TSC_ASMS_MASK);
+}
+
+static inline void pch_ttm_imask_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Disable Target Time Interrupt */
+ PCH_CLR_ADDR_BIT(p + PCH_TSC_OFFSET, PCH_TSC_TTM_MASK);
+}
+
+static inline void pch_block_reset(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Reset Hardware Assist block */
+ PCH_SET_ADDR_BIT(p + PCH_TSC_OFFSET, PCH_TSC_RESET);
+
+ PCH_CLR_ADDR_BIT(p + PCH_TSC_OFFSET, PCH_TSC_RESET);
+}
+
+static inline u32 pch_pps_evt_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Poll for PPS event */
+ return PCH_BIT_SET_CHECK(p + PCH_TSE_OFFSET, PCH_TSE_PPS);
+}
+
+static inline u32 pch_amms_evt_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Poll for Auxiliary Master Mode Snapshot Captured event */
+ return PCH_BIT_SET_CHECK(p + PCH_TSE_OFFSET, PCH_TSE_SNM);
+}
+
+static inline u32 pch_asms_evt_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Poll for Auxiliary Slave Mode Snapshot Captured event */
+ return PCH_BIT_SET_CHECK(p + PCH_TSE_OFFSET, PCH_TSE_SNS);
+}
+
+static inline u32 pch_ttm_evt_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Poll for Target Time Reached event */
+ return PCH_BIT_SET_CHECK(p + PCH_TSE_OFFSET, PCH_TSE_TTIPEND);
+}
+
+static inline void pch_pps_evt_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Clear PPS event */
+ PCH_SET_ADDR_BIT(p + PCH_TSE_OFFSET, PCH_TSE_PPS);
+}
+
+static inline void pch_amms_evt_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Clear Auxiliary Master Mode Snapshot Captured event */
+ PCH_SET_ADDR_BIT(p + PCH_TSE_OFFSET, PCH_TSE_SNM);
+}
+
+static inline void pch_asms_evt_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Clear Auxiliary Slave Mode Snapshot Captured event */
+ PCH_SET_ADDR_BIT(p + PCH_TSE_OFFSET, PCH_TSE_SNS);
+}
+
+static inline void pch_ttm_evt_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Clear Target Time Reached event */
+ PCH_SET_ADDR_BIT(p + PCH_TSE_OFFSET, PCH_TSE_TTIPEND);
+}
+
+/**
+ * pch_sys_snap_set() - Set System Time value
+ * @sys_time_low: The system time low.
+ * @sys_time_high: The system time high.
+ */
+static inline void pch_sys_snap_set(u32 sys_time_low, u32 sys_time_high,
+ struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Update the System Time Low Register contents */
+ PCH_REG_32_WRITE(p + PCH_STL_OFFSET, sys_time_low);
+
+ /* Update the System Time High Register contents */
+ PCH_REG_32_WRITE(p + PCH_STH_OFFSET, sys_time_high);
+}
+
+/**
+ * pch_sys_snap_get() - Get System Time Low value
+ * @sys_time_low: The system time low.
+ * @sys_time_high: The system time high.
+ */
+static inline void pch_sys_snap_get(u32 *sys_time_low, u32 *sys_time_high,
+ struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get the System Time Low Register contents */
+ PCH_REG_32_READ(p + PCH_STL_OFFSET, sys_time_low);
+
+ /* Get the System Time High Register contents */
+ PCH_REG_32_READ(p + PCH_STH_OFFSET, sys_time_high);
+}
+
+/**
+ * pch_tgt_snap_set() - Set Target Time value
+ * @tgt_time_low: The target time low.
+ * @tgt_time_high: The target time high.
+ */
+static inline void pch_tgt_snap_set(u32 tgt_time_low, u32 tgt_time_high,
+ struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Update the Target Time Low Register contents */
+ PCH_REG_32_WRITE(p + PCH_TTL_OFFSET, tgt_time_low);
+
+ /* Update the Target Time High Register contents */
+ PCH_REG_32_WRITE(p + PCH_TTH_OFFSET, tgt_time_high);
+}
+
+/**
+ * pch_tgt_snap_get() - et Target Time value
+ * @tgt_time_low: The target time low.
+ * @tgt_time_high: The target time high.
+ */
+static inline void pch_tgt_snap_get(u32 *tgt_time_low, u32 *tgt_time_high,
+ struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get the Target Time Low Register contents */
+ PCH_REG_32_READ(p + PCH_TTL_OFFSET, tgt_time_low);
+
+ /* Get the Target Time High Register contents */
+ PCH_REG_32_READ(p + PCH_TTH_OFFSET, tgt_time_high);
+}
+
+/**
+ * pch_addend_set() - Set Frequency Scaling Value
+ * @fsv: Frequency.
+ */
+static inline void pch_addend_set(u32 fsv, struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Update the Addend Register contents */
+ PCH_REG_32_WRITE(p + PCH_ADD_OFFSET, fsv);
+}
+
+/**
+ * pch_addend_get() - Get Frequency Scaling Value
+ * @fsv: The frequency.
+ * One can provide multiple line descriptions
+ * for arguments.
+ */
+static inline void pch_addend_get(u32 *fsv, struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get the Addend Register contents */
+ PCH_REG_32_READ(p + PCH_ADD_OFFSET, fsv);
+}
+
+/**
+ * pch_pps_set() - Set Pulse Per Second Value
+ * @pps: The pulse per second value.
+ */
+static inline void pch_pps_set(u32 pps, struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Update the PPS Compare Register contents */
+ PCH_REG_32_WRITE(p + PCH_PPS_OFFSET, pps);
+}
+
+/**
+ * pch_pps_get() - Get Pulse Per Second Value
+ * @pps: Get Pulse Per Second Value.
+ */
+static inline void pch_pps_get(u32 *pps, struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get the PPS Compare Register contents */
+ PCH_REG_32_READ(p + PCH_PPS_OFFSET, pps);
+}
+
+/**
+ * pch_aux_master_snap_get() - Get AMMS value
+ * @amms_low: AMMS low value.
+ * @amms_high: AMMS high value.
+ */
+static inline void pch_aux_master_snap_get(u32 *amms_low, u32 *amms_high,
+ struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get the Auxiliary Master Mode Snapshot Low Register contents */
+ PCH_REG_32_READ(p + PCH_AMSL_OFFSET, amms_low);
+
+ /* Get the Auxiliary Master Mode Snapshot High Register contents */
+ PCH_REG_32_READ(p + PCH_AMSH_OFFSET, amms_high);
+}
+
+/**
+ * pch_aux_slave_snap_get() - Get ASMS value
+ * @asms_low: The ASMS low value.
+ * @asms_high: The ASMS high value.
+ */
+static inline void pch_aux_slave_snap_get(u32 *asms_low, u32 *asms_high,
+ struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get the Auxiliary Slave Mode Snapshot Low Register contents */
+ PCH_REG_32_READ(p + PCH_ASSL_OFFSET, asms_low);
+
+ /* Get the Auxiliary Slave Mode Snapshot High Register contents */
+ PCH_REG_32_READ(p + PCH_ASSH_OFFSET, asms_high);
+}
+
+/**
+ * pch_master_mode_set() - Set the channel mode to 1588 Master/Slave
+ * @master_mode: The channel mode.
+ */
+static inline void pch_master_mode_set(u32 master_mode, struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* SET or CLEAR the Master Mode */
+ if (master_mode) {
+ /* SET the mm bit */
+ PCH_SET_ADDR_BIT(p + PCH_CC_OFFSET, PCH_CC_MM);
+ } else {
+ /* CLEAR the mm bit */
+ PCH_CLR_ADDR_BIT(p + PCH_CC_OFFSET, PCH_CC_MM);
+ }
+}
+
+static inline u32 pch_master_mode_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Check for 1588 master mode of channel */
+ return PCH_BIT_SET_CHECK(p + PCH_CC_OFFSET, PCH_CC_MM);
+}
+
+/**
+ * pch_timestamp_all_set() - Set Timestamp all or only PTP messages flag
+ * @all_msg: All/PTP messages.
+ */
+static inline void pch_timestamp_all_set(u32 all_msg, struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* SET or CLEAR the All Message Timestamping */
+ if (all_msg) {
+ /* SET the ta bit */
+ PCH_SET_ADDR_BIT(p + PCH_CC_OFFSET, PCH_CC_TA);
+ } else { /* else of if (TRUE == all_msg) */
+ /* CLEAR the ta bit */
+ PCH_CLR_ADDR_BIT(p + PCH_CC_OFFSET, PCH_CC_TA);
+ }
+}
+
+static inline u32 pch_timestamp_all_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Check for Timestamp all OR only PTP messages flag */
+ return PCH_BIT_SET_CHECK(p + PCH_CC_OFFSET, PCH_CC_TA);
+}
+
+/**
+ * pch_version_set() - Set the 1588 version number
+ * @version_val: The version value.
+ */
+static inline void pch_version_set(u32 version_val, struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ if (version_val == TRUE) {
+ /* SET the version bit */
+ PCH_SET_ADDR_BIT(p + PCH_CC_OFFSET, PCH_CC_VERSION);
+ } else {
+ /* CLEAR the version bit */
+ PCH_CLR_ADDR_BIT(p + PCH_CC_OFFSET, PCH_CC_VERSION);
+ }
+}
+
+static inline u32 pch_version_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get the 1588 version number */
+ return PCH_BIT_SET_CHECK(p + PCH_CC_OFFSET, PCH_CC_VERSION);
+}
+
+static inline u32 pch_can_snap_valid(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* CAN Timestamp available */
+ return PCH_BIT_SET_CHECK(p + PCH_CCE_OFFSET, PCH_CE_VAL);
+}
+
+static inline u32 pch_can_snap_ovr(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* CAN Timestamp overrun */
+ return PCH_BIT_SET_CHECK(p + PCH_CCE_OFFSET, PCH_CE_OVR);
+}
+
+static inline void pch_can_snap_valid_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Clear CAN Timestamp valid flag */
+ PCH_REG_32_WRITE(p + PCH_CCE_OFFSET, PCH_CE_VAL);
+}
+
+static inline void pch_can_snap_ovr_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Clear CAN Timestamp overrun flag */
+ PCH_REG_32_WRITE(p + PCH_CCE_OFFSET, PCH_CE_OVR);
+}
+
+static inline u32 pch_rx_snap_evt(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Receive Timestamp available */
+ return PCH_BIT_SET_CHECK(p + PCH_CE_OFFSET, PCH_CE_RXS);
+}
+
+static inline u32 pch_tx_snap_evt(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Transmit Timestamp available */
+ return PCH_BIT_SET_CHECK(p + PCH_CE_OFFSET, PCH_CE_TXS);
+}
+
+static inline void pch_rx_snap_evt_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Clear Receive Timestamp available event */
+ PCH_REG_32_WRITE(p + PCH_CE_OFFSET, PCH_CE_RXS);
+}
+
+static inline void pch_tx_snap_evt_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Clear Transmit Timestamp available event */
+ PCH_REG_32_WRITE(p + PCH_CE_OFFSET, PCH_CE_TXS);
+}
+
+/**
+ * pch_can_snap_get() - Get PTP CAN Port Timestamp value
+ * @rxs_low: The CAN Rx low value.
+ * @rxs_high: The CAN Rx high value.
+ */
+static inline void pch_can_snap_get(u32 *rxs_low, u32 *rxs_high,
+ struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get the Receive Timestamp/Snapshot Low Register contents */
+ PCH_REG_32_READ(p + PCH_CXSL_OFFSET, rxs_low);
+
+ /* Get the Receive Timestamp/Snapshot High Register contents */
+ PCH_REG_32_READ(p + PCH_CXSH_OFFSET, rxs_high);
+}
+
+/**
+ * pch_rx_snap_get() - Get PTP Port Rx Timestamp value
+ * @rxs_low: The Snap Rx value.
+ * @rxs_high: The Snap Rx Value.
+ */
+static inline void pch_rx_snap_get(u32 *rxs_low, u32 *rxs_high,
+ struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get the Receive Timestamp/Snapshot Low Register contents */
+ PCH_REG_32_READ(p + PCH_RSL_OFFSET, rxs_low);
+
+ /* Get the Receive Timestamp/Snapshot High Register contents */
+ PCH_REG_32_READ(p + PCH_RSH_OFFSET, rxs_high);
+}
+
+/**
+ * pch_tx_snap_get() - Get PTP Port Tx Timestamp value
+ * @txs_low: The Port Tx value low.
+ * @txs_high: The Port Tx value high.
+ */
+static inline void pch_tx_snap_get(u32 *txs_low, u32 *txs_high,
+ struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get the Transmit Timestamp/Snapshot Low Register contents */
+ PCH_REG_32_READ(p + PCH_XSL_OFFSET, txs_low);
+
+ /* Get the Transmit Timestamp/Snapshot High Register contents */
+ PCH_REG_32_READ(p + PCH_XSH_OFFSET, txs_high);
+}
+
+/**
+ * pch_uuid_seqid_get() - Get UUID and Sequence ID of PTP message
+ * @uuid_low: The UUID low value.
+ * @uuid_high: The UUID high value.
+ * @seq_id: The sequence ID.
+ */
+static inline void pch_uuid_seqid_get(u32 *uuid_low, u32 *uuid_high,
+ u32 *seq_id, struct pch_dev *chip)
+{
+ u32 regval;
+ void __iomem *p = chip->mem_virt;
+
+ /* Get the UUID Low Register contents */
+ PCH_REG_32_READ(p + PCH_UID_OFFSET, uuid_low);
+
+ /* Get the Sequence ID and Source UUID High Register contents */
+ PCH_REG_32_READ(p + PCH_SID_OFFSET, &regval);
+
+ *seq_id = regval >> PCH_SID_LOC;
+ *uuid_high = regval & PCH_LSB_SHORT_MASK;
+}
+
+/**
+ * pch_op_mode_set() - Sets the operation mode
+ * @mode: Sets the operation mode.
+ */
+static inline void pch_op_mode_set(u32 mode, struct pch_dev *chip)
+{
+ u32 regval;
+ void __iomem *p = chip->mem_virt;
+
+ PCH_REG_32_READ(p + PCH_CC_OFFSET, &regval);
+ regval = (regval & ~PCH_CC_MODE_MASK) | (mode << PCH_CC_MODE_SHIFT);
+ /* set the operaion mode bits */
+ PCH_REG_32_WRITE(p + PCH_CC_OFFSET, regval);
+}
+
+static inline u32 pch_op_mode_get(struct pch_dev *chip)
+{
+ u32 regval;
+ u32 mode;
+ void __iomem *p = chip->mem_virt;
+
+ PCH_REG_32_READ(p + PCH_CC_OFFSET, &regval);
+ /* get the operaion mode bits */
+ mode = (regval & PCH_CC_MODE_MASK) >> PCH_CC_MODE_SHIFT;
+
+ return mode;
+}
+
+static inline void pch_eth_enable_set(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* SET the eth_enable bit */
+ PCH_SET_ADDR_BIT(p + PCH_ECS_OFFSET, PCH_ECS_ETH);
+}
+
+static inline void pch_eth_enable_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Clear the eth_enable bit */
+ PCH_CLR_ADDR_BIT(p + PCH_ECS_OFFSET, PCH_ECS_ETH);
+}
+
+static inline u32 pch_eth_enable_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Is eth_enable bit set? */
+ return PCH_BIT_SET_CHECK(p + PCH_ECS_OFFSET, PCH_ECS_ETH);
+}
+
+static inline void pch_can_enable_set(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* SET the can_enable bit */
+ PCH_SET_ADDR_BIT(p + PCH_ECS_OFFSET, PCH_ECS_CAN);
+}
+
+static inline void pch_can_enable_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Clear the can_enable bit */
+ PCH_CLR_ADDR_BIT(p + PCH_ECS_OFFSET, PCH_ECS_CAN);
+}
+
+static inline u32 pch_can_enable_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Gets the CAN enable status */
+ return PCH_BIT_SET_CHECK(p + PCH_ECS_OFFSET, PCH_ECS_CAN);
+}
+
+/**
+ * pch_station_set() - Set the station[1-6] address to be used in
+ * PTP message
+ * @station: station ID.
+ * @value: station address value.
+ */
+static inline void
+pch_station_set(u32 station, u32 value, struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Set the Station Address Register contents */
+ PCH_REG_32_WRITE(p + PCH_STA_OFFSET + station * sizeof(s32), value);
+}
+
+/**
+ * pch_station_get() - Get the station[1-6] address used in PTP message
+ * @station: station ID.
+ * @value: Pointer to set station address value.
+ */
+static inline u32 pch_station_get(u32 station, struct pch_dev *chip)
+{
+ u32 value;
+ void __iomem *p = chip->mem_virt;
+
+ /* Get the Station Address Register contents */
+ PCH_REG_32_READ(p + PCH_STA_OFFSET + station * sizeof(s32), &value);
+ value &= 0xFF; /* only one byte */
+
+ return value;
+}
+
+static enum pch_status pch_disable_interrupts(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ if (p != 0) {
+ pch_ttm_imask_clear(chip);
+ pch_asms_imask_clear(chip);
+ pch_amms_imask_clear(chip);
+ pch_pps_imask_clear(chip);
+ }
+ return 0;
+}
+
+/**
+ * pch_interrupt_pending() - Check whether there is any pending interrupts
+ * from the 1588 device
+ * @pending: Pending flag which set to TRUE if there is any pending
+ * interrupt.
+ * @pch_pdata: Private data for PCH.
+ */
+static u32 pch_interrupt_pending(struct pch_dev *pch_pdata)
+{
+ u32 pending;
+
+ if (pch_pps_evt_get(pch_pdata) || pch_amms_evt_get(pch_pdata) ||
+ pch_asms_evt_get(pch_pdata) || pch_ttm_evt_get(pch_pdata)) {
+ pending = FALSE;
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:interrupt pending\n", __func__);
+ pending = TRUE;
+ } else {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:NO interrupt pending\n", __func__);
+ }
+ return pending;
+}
+
+/**
+ * pch_port_mode_get() - Function to determine the port mode
+ * @ptpport: Interested port (GBE_0).
+ * @qq: aa.
+ */
+static enum pch_ptpportmode
+pch_port_mode_get(enum pch_ptpport ptpport, struct pch_dev *pch_pdata)
+{
+ /* Local variables */
+ u32 master_mode = FALSE;
+ u32 any_mode = FALSE;
+ enum pch_ptpportmode port_mode = PCH_1588PTP_PORT_SLAVE;
+
+ /* Get the Mode of the PTP Port */
+ master_mode = pch_master_mode_get(pch_pdata);
+ any_mode = pch_timestamp_all_get(pch_pdata);
+
+ /* Is ANY mode (all message timestamp mode) on? */
+ if (any_mode) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:all messages being timestamped\n", __func__);
+ /*
+ * When Any mode is set, all messages are time stamped,
+ * irrespective of the Master/Slave mode bit
+ */
+ port_mode = PCH_1588PTP_PORT_ANYMODE;
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:port_mode = PCH_1588PTP_PORT_ANYMODE\n", __func__);
+ } else {
+ /* Is Master mode on? */
+ if (master_mode) {
+ port_mode = PCH_1588PTP_PORT_MASTER;
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:port_mode = PCH_1588PTP_PORT_MASTER\n", __func__);
+ } else {
+ port_mode = PCH_1588PTP_PORT_SLAVE;
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:port_mode = PCH_1588PTP_PORT_SLAVE\n", __func__);
+ }
+ }
+
+ return port_mode;
+}
+
+/**
+ * pch_blpl_base_address_set() - Function sets the virtual address of
+ * registers
+ * @base_addr: Virtual address of IEEE 1588 module registers.
+ *
+ * This API will set the starting virtual addresses for the 1588 hardware
+ * registers.
+ */
+static void pch_blpl_base_address_set(struct pch_dev *chip)
+{
+ /* Initialize the callback pointers */
+ pch_tt_cbptr = NULL;
+ pch_am_cbptr = NULL;
+ pch_as_cbptr = NULL;
+ pch_pps_cbptr = NULL;
+
+ /* Reset the statistics counters */
+ pch_stats.rxmsgs = pch_stats.txmsgs = 0;
+
+ /* Clear availability of various events */
+ pch_pps_evt_clear(chip);
+ pch_ttm_evt_clear(chip);
+ pch_amms_evt_clear(chip);
+ pch_asms_evt_clear(chip);
+}
+
+/**
+ * pch_ptp_port_config_set() - Configure IEEE 1588 Hardware Assist message
+ * detection on a given PTP port
+ * @ptpport: port on which PTP message detection to be enabled.
+ * @ptpportmode: Master/Slave/All messages.
+ *
+ * This API enables the time stamping on a particular PTP port.
+ */
+static enum pch_status
+pch_ptp_port_config_set(enum pch_ptpport ptpport,
+ enum pch_ptpportmode ptpportmode,
+ struct pch_dev *pch_pdata)
+{
+ u32 master_mode, timestamp_set;
+ /* Verify the parameters for proper values */
+ if (ptpport != PCH_GBE_0_1588PTP_PORT) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s:invalid ptp port returning PCH_GBE_0_1588PTP_PORT\n",
+ __func__);
+ return PCH_INVALIDPARAM;
+ }
+
+ if (ptpportmode == PCH_1588PTP_PORT_MASTER) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:port_mode=PCH_1588PTP_PORT_MASTER\n", __func__);
+ master_mode = TRUE;
+ timestamp_set = FALSE;
+ } else if (ptpportmode == PCH_1588PTP_PORT_SLAVE) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:port_mode=PCH_1588PTP_PORT_SLAVE\n", __func__);
+ master_mode = FALSE;
+ timestamp_set = FALSE;
+ } else if (ptpportmode == PCH_1588PTP_PORT_ANYMODE) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:port_mode=PCH_1588PTP_PORT_ANYMODE\n", __func__);
+ master_mode = FALSE;
+ timestamp_set = TRUE;
+ } else {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s: Invalid Port Mode (%d) returning "
+ "PCH_INVALIDPARAM\n", __func__, ptpportmode);
+ return PCH_INVALIDPARAM;
+ }
+ pch_master_mode_set(master_mode, pch_pdata);
+ pch_timestamp_all_set(timestamp_set, pch_pdata);
+
+ return 0;
+}
+
+/**
+ * pch_ptp_port_config_get() - Get the configuration of IEEE 1588 Hardware
+ * Assist message detection for given PTP port
+ * @ptpport: port for which PTP message configuration to be obtained.
+ * @ptpportmode: Master/Slave/All messages.
+ *
+ * This API retrieves the time stamping configuration of the given PTP port.
+ */
+static enum pch_status
+pch_ptp_port_config_get(enum pch_ptpport ptpport,
+ enum pch_ptpportmode *ptpportmode,
+ struct pch_dev *pch_pdata)
+{
+ /* Verify the parameters for proper values */
+ if ((ptpport != PCH_GBE_0_1588PTP_PORT) ||
+ (ptpportmode == (enum pch_ptpportmode *) NULL)) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s:invalid port_mode or port returning PCH_INVALIDPARAM\n",
+ __func__);
+ return PCH_INVALIDPARAM;
+ }
+
+ /* Get the Mode of the PTP Port */
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking pch_port_mode_get\n", __func__);
+ *ptpportmode = pch_port_mode_get(ptpport, pch_pdata);
+
+ return 0;
+}
+
+/**
+ * pch_ptp_rx_poll() - Poll the IEEE 1588 Hardware Assist receive side
+ * message/time stamp detection status for given PTP
+ * Port
+ * @ptpport: port on which time stamp availability to be checked.
+ * @ptpmsgdata: Captured time stamp and other message information.
+ *
+ * This API will poll for the availability of a time stamp on the received
+ * Sync (in slave mode) or Delay_Req (in master mode) messages.
+ */
+static enum pch_status
+pch_ptp_rx_poll(enum pch_ptpport ptpport, struct pch_ptpmsgdata *ptpmsgdata,
+ struct pch_dev *pch_pdata)
+{
+ u32 locked_mode = FALSE;
+
+ enum pch_ptpportmode port_mode = PCH_1588PTP_PORT_MODE_INVALID;
+ enum pch_ptpversion ptpversion = PCH_1588PTP_VERSION_INVALID;
+ enum pch_ptpope_mode op_mode = PCH_1588PTP_OP_MODE_INVALID;
+
+ /* Verify the parameters for proper values */
+ if ((ptpport != PCH_GBE_0_1588PTP_PORT) ||
+ (ptpmsgdata == (struct pch_ptpmsgdata *) NULL)) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s:invalid port or ptp message "
+ "returning PCH_INVALIDPARAM\n", __func__);
+ return PCH_INVALIDPARAM;
+ }
+
+ /* Get the PTP version */
+ ptpversion = pch_version_get(pch_pdata);
+
+ /* check if locked/unlocked mode */
+ if (ptpversion == PCH_1588PTP_VERSION_0) { /* PTP v1 only */
+ /* Get the Mode of the PTP Port if only PTPv1 is supported */
+ port_mode = pch_port_mode_get(ptpport, pch_pdata);
+ if (port_mode != PCH_1588PTP_PORT_ANYMODE)
+ locked_mode = TRUE;
+ } else { /* PTP v1 & v2 */
+
+ /* get operation mode */
+ op_mode = pch_op_mode_get(pch_pdata);
+ if ((op_mode != PCH_1588PTP_OP_MODE_V1_ALL_MSGS) &&
+ (op_mode != PCH_1588PTP_OP_MODE_V1_V2_ALL_MSGS)) {
+ locked_mode = TRUE;
+ }
+ }
+
+ /* if locked mode,check event flag */
+ if (locked_mode && (!pch_rx_snap_evt(pch_pdata))) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:locked mode-event flag not set. "
+ "NO TIMESTAMP returning PCH_NOTIMESTAMP\n", __func__);
+ return PCH_NOTIMESTAMP;
+ }
+
+ /* Fetch the receive timestamp */
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking pch_rx_snap_get\n", __func__);
+
+ pch_rx_snap_get(&ptpmsgdata->ptptimestamp.tim_val_low_word,
+ &ptpmsgdata->ptptimestamp.tim_val_high_word, pch_pdata);
+
+ dev_dbg(&pch_pdata->pdev->dev, "%s Snapshot (Hi:Low): %x : %x\n",
+ __func__, ptpmsgdata->ptptimestamp.tim_val_high_word,
+ ptpmsgdata->ptptimestamp.tim_val_low_word);
+
+ /* Fetch the UUID & Seq# of PTP messages in 'Master/Slave Mode' only */
+ if ((locked_mode) && (PCH_1588PTP_VERSION_0 == ptpversion)) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking pch_uuid_seqid_get\n", __func__);
+ pch_uuid_seqid_get(&ptpmsgdata->ptpuuid.uuid_val_low_word,
+ &ptpmsgdata->ptpuuid.
+ uuid_val_high_half_word,
+ &ptpmsgdata->ptpsequencenumber,
+ pch_pdata);
+ }
+ /* Clear-off the UUID & Seq# of all the messages in 'Any Mode' */
+ else {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:port mode is ANYMODE,clearing off UUID & SeqNumber\n",
+ __func__);
+ ptpmsgdata->ptpuuid.uuid_val_low_word = 0;
+ ptpmsgdata->ptpuuid.uuid_val_high_half_word = 0;
+ ptpmsgdata->ptpsequencenumber = 0;
+ }
+
+ /* Increment receive timestamp counter
+ * Note:In unlocked modes,this will get incremented
+ * for every rx time stamp poll.
+ */
+ pch_stats.rxmsgs++;
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:incremented rcv timestamp counter=%d\n",
+ __func__, pch_stats.rxmsgs);
+
+ /*
+ * Fill-in the PTP message type.This can be done
+ * only when PTP v1 alone is supported and mode
+ * is master/slave.Set the message type as unknown
+ * for all other cases.
+ */
+ if (ptpversion == PCH_1588PTP_VERSION_0) { /* PTP v1 only */
+ switch (port_mode) {
+ case PCH_1588PTP_PORT_MASTER:
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PTP message type=PCH_1588PTP_MSGTYP"
+ "E_DELAYREQ\n", __func__);
+ ptpmsgdata->ptpmsgtype = PCH_1588PTP_MSGTYPE_DELAYREQ;
+ break;
+ case PCH_1588PTP_PORT_SLAVE:
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PTP message type=PCH_1588PTP_MSGTYP"
+ "E_SYNC\n", __func__);
+ ptpmsgdata->ptpmsgtype = PCH_1588PTP_MSGTYPE_SYNC;
+ break;
+ case PCH_1588PTP_PORT_ANYMODE:
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PTP message type=PCH_1588PTP_MSGTYP"
+ "E_UNKNOWN\n", __func__);
+ ptpmsgdata->ptpmsgtype = PCH_1588PTP_MSGTYPE_UNKNOWN;
+ break;
+ default:
+ dev_err(&pch_pdata->pdev->dev,
+ "%s: Invalid Port "
+ "Mode returning PCH_FAILED\n", __func__);
+ return PCH_FAILED;
+ }
+ } else { /* PTP v1 & v2 */
+
+ dev_dbg(&pch_pdata->pdev->dev, "%s:PTP message type="
+ "PCH_1588PTP_MSGTYPE_UNKNOWN\n", __func__);
+ ptpmsgdata->ptpmsgtype = PCH_1588PTP_MSGTYPE_UNKNOWN;
+ }
+
+ /* If locked mode allow next timestamp to be captured */
+ if (locked_mode) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking pch_rx_snap_evt_clear\n", __func__);
+ pch_rx_snap_evt_clear(pch_pdata);
+ }
+
+ return 0;
+}
+
+/**
+ * pch_ptp_tx_poll() - Poll the IEEE 1588 Hardware Assist transmit side
+ * message/time stamp detection status for given PTP
+ * Port
+ * @ptpport: port on which time stamp availability to be checked.
+ * @ptpmsgdata: Captured time stamp and other message information.
+ *
+ * This API will poll for the availability of a time stamp on the transmit side
+ * Sync (in master mode) or Delay_Req (in slave mode) messages.
+ */
+static enum pch_status
+pch_ptp_tx_poll(enum pch_ptpport ptpport, struct pch_ptpmsgdata *ptpmsgdata,
+ struct pch_dev *pch_pdata)
+{
+ u32 locked_mode = FALSE;
+
+ enum pch_ptpportmode port_mode = PCH_1588PTP_PORT_MODE_INVALID;
+ enum pch_ptpversion ptpversion = PCH_1588PTP_VERSION_INVALID;
+ enum pch_ptpope_mode op_mode = PCH_1588PTP_OP_MODE_INVALID;
+
+ /* Verify the parameters for proper values */
+ if ((ptpport != PCH_GBE_0_1588PTP_PORT) ||
+ (ptpmsgdata == (struct pch_ptpmsgdata *) NULL)) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s:invalid port or ptp message "
+ "returning PCH_INVALIDPARAM\n", __func__);
+ return PCH_INVALIDPARAM;
+ }
+
+ /* Get the PTP version */
+ ptpversion = pch_version_get(pch_pdata);
+
+ /*check if locked/unlocked mode */
+ if (ptpversion == PCH_1588PTP_VERSION_0) { /* PTP v1 only */
+ /* Get the Mode of the PTP Port if only PTPv1 is supported */
+ port_mode = pch_port_mode_get(ptpport, pch_pdata);
+ if (port_mode != PCH_1588PTP_PORT_ANYMODE)
+ locked_mode = TRUE;
+ } else { /* PTP v1 & v2 */
+
+ /* get operation mode */
+ op_mode = pch_op_mode_get(pch_pdata);
+ if ((op_mode != PCH_1588PTP_OP_MODE_V1_ALL_MSGS) &&
+ (op_mode != PCH_1588PTP_OP_MODE_V1_V2_ALL_MSGS)) {
+ locked_mode = TRUE;
+ }
+ }
+
+ /* if locked mode,check event flag */
+ if ((locked_mode) && (!pch_tx_snap_evt(pch_pdata))) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:locked mode-event flag not set."
+ "NO TIMESTAMP returning PCH_NOTIMESTAMP\n", __func__);
+ return PCH_NOTIMESTAMP;
+ }
+
+ /* read time stamp registers */
+ pch_tx_snap_get(&ptpmsgdata->ptptimestamp.tim_val_low_word,
+ &ptpmsgdata->ptptimestamp.tim_val_high_word, pch_pdata);
+
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:Snapshot (Hi:Low): %x : %x\n", __func__,
+ ptpmsgdata->ptptimestamp.tim_val_high_word,
+ ptpmsgdata->ptptimestamp.tim_val_low_word);
+ /*
+ * Fill the UUID and Seq# with invalid values (zeros)
+ * since they are not relevant for transmit timestamp
+ */
+ ptpmsgdata->ptpuuid.uuid_val_low_word = 0;
+ ptpmsgdata->ptpuuid.uuid_val_high_half_word = 0;
+ ptpmsgdata->ptpsequencenumber = 0;
+
+ /*
+ * Increment transmit timestamp counter
+ * Note:In unlocked modes,this will get incremented
+ * for every tx time stamp poll
+ */
+ pch_stats.txmsgs++;
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:incremented tx timestamp counter=%d\n", __func__,
+ pch_stats.txmsgs);
+
+ /*
+ * Fill-in the PTP message type.This can be done
+ * only when PTP v1 alone is supported and mode
+ * is master/slave.Set the message type as unknown
+ * for all other cases.
+ */
+ if (ptpversion == PCH_1588PTP_VERSION_0) { /* PTP v1 only */
+ switch (port_mode) {
+ case PCH_1588PTP_PORT_MASTER:
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PTP message type="
+ "PCH_1588PTP_MSGTYPE_SYNC\n", __func__);
+ ptpmsgdata->ptpmsgtype = PCH_1588PTP_MSGTYPE_SYNC;
+ break;
+ case PCH_1588PTP_PORT_SLAVE:
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PTP message type="
+ "PCH_1588PTP_MSGTYPE_DELAYREQ\n", __func__);
+ ptpmsgdata->ptpmsgtype = PCH_1588PTP_MSGTYPE_DELAYREQ;
+ break;
+ case PCH_1588PTP_PORT_ANYMODE:
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PTP message type="
+ "PCH_1588PTP_MSGTYPE_UNKNOWN\n", __func__);
+ ptpmsgdata->ptpmsgtype = PCH_1588PTP_MSGTYPE_UNKNOWN;
+ break;
+ default:
+ dev_err(&pch_pdata->pdev->dev,
+ "%s: Invalid Port Mode returning PCH_FAILED\n",
+ __func__);
+ return PCH_FAILED;
+ }
+ } else { /* PTP v1 & v2 */
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PTP message type="
+ "PCH_1588PTP_MSGTYPE_UNKNOWN\n", __func__);
+ ptpmsgdata->ptpmsgtype = PCH_1588PTP_MSGTYPE_UNKNOWN;
+ }
+
+ /* If locked mode allow next timestamp to be captured */
+ if (locked_mode) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking pch_tx_snap_evt_clear\n", __func__);
+ pch_tx_snap_evt_clear(pch_pdata);
+ }
+
+ return 0;
+}
+
+/**
+ * pch_system_time_set() - Sets the system time to given value
+ * @systemTime: value to set the system time.
+ */
+static enum pch_status pch_system_time_set(struct pch_tim_val systemTime,
+ struct pch_dev *chip)
+{
+ u32 old_fsv;
+
+ /* Retrieve old Frequency Scaling Value */
+ pch_addend_get(&old_fsv, chip);
+
+ /*
+ * Set the Frequency Scaling Value to zero (0) so that
+ * System Time doesn't get incremented while it is being written to
+ */
+ pch_addend_set(0, chip);
+
+ /* Update System Time with user specified values */
+ pch_sys_snap_set(systemTime.tim_val_low_word,
+ systemTime.tim_val_high_word, chip);
+
+ /*
+ * Let the hardware assist re-evaluate the target time reached
+ * condition based on the new system time
+ */
+ pch_ttm_evt_clear(chip);
+
+ /*
+ * Restore old Frequency Scaling Value so that System Time
+ * can be incremented
+ */
+ pch_addend_set(old_fsv, chip);
+
+ return 0;
+}
+
+/**
+ * pch_system_time_get() - Gets the System Time from the IEEE 1588 hardware
+ * assist block
+ * @systemTime: Address to which system time is to be returned.
+ * @qq: aa.
+ */
+static enum pch_status pch_system_time_get(struct pch_tim_val *systemTime,
+ struct pch_dev *chip)
+{
+ /* Verify the parameter */
+ if (systemTime == (struct pch_tim_val *) NULL)
+ return PCH_INVALIDPARAM;
+
+ /* Fetch System Time */
+ pch_sys_snap_get(&systemTime->tim_val_low_word,
+ &systemTime->tim_val_high_word, chip);
+
+ return 0;
+}
+
+/**
+ * pch_tick_rate_set() - Sets the Frequency Scaling Value in the IEEE 1588
+ * hardware assist block
+ * @tickrate: Frequency scaling value.
+ *
+ * This API sets the Tick Rate (Frequency Scaling Value) in the IEEE 1588 block.
+ * This value determines the progress at which the System time advances.
+ * Note: For the A1 hardware sample, the addend register value configured in
+ * the hardware is calculated as follows:
+ * Addend register value = Logical right shift tickrate by 1 and set MSB to 1
+ */
+static enum pch_status pch_tick_rate_set(u32 tickrate, struct pch_dev *chip)
+{
+ /* Update the Frequency Scaling Value */
+ pch_addend_set(tickrate, chip);
+
+ return 0;
+}
+
+/**
+ * pch_tick_rate_get() - Gets the Frequency Scaling Value from the
+ * IEEE 1588 hardware assist block
+ * @tickrate: Address where current Frequency scaling value is returned.
+ *
+ * This API gets the Tick Rate (Frequency Scaling Value) used in the IEEE 1588
+ * block.This value determines the progress at which the System time advances.
+ */
+static enum pch_status pch_tick_rate_get(u32 *tickrate, struct pch_dev *chip)
+{
+ /* Verify the parameter */
+ if (tickrate == (u32 *)NULL)
+ return PCH_INVALIDPARAM;
+
+ /* Retrieve Current Frequency Scaling Value */
+ pch_addend_get(tickrate, chip);
+
+ return 0;
+}
+
+/**
+ * pch_target_time_interrupt_enable() - Enable the target time
+ * reached/exceeded system time
+ * interrupt
+ * @callBack: Routine to be invoked when target time reached interrupt occurs.
+ */
+static enum pch_status pch_target_time_interrupt_enable
+ (void (*callBack) (struct pch_tim_val, struct pch_dev *),
+ struct pch_dev *chip)
+{
+ /* Verify the parameter */
+ if (callBack == NULL)
+ return PCH_INVALIDPARAM;
+
+ /* Register the Callback */
+ pch_tt_cbptr = callBack;
+
+ /* Set target time interrupt mask */
+ pch_ttm_imask_set(chip);
+
+ return 0;
+}
+
+static enum pch_status pch_target_time_interrupt_disable(struct pch_dev *chip)
+{
+ /* Clear target time interrupt mask */
+ pch_ttm_imask_clear(chip);
+
+ /* Unregister the Callback */
+ pch_tt_cbptr = NULL;
+
+ return 0;
+}
+
+
+/**
+ * pch_target_time_poll() - Poll to verify whether the System time is
+ * greater or equal to the Target time in the
+ * IEEE 1588 hardware assist block.
+ * @ttm_poll_flag: Flag means like below
+ * TRUE if target time has reached system time
+ * FALSE if target time has not reached system time
+ * @target_tim: Snap shot of target time captured.
+ */
+static enum pch_status
+pch_target_time_poll(u32 *ttm_poll_flag,
+ struct pch_tim_val *target_tim, struct pch_dev *pch_pdata)
+{
+ unsigned long flags;
+ /* Verify the parameters */
+ if ((ttm_poll_flag == (u32 *)NULL) ||
+ (target_tim == (struct pch_tim_val *) NULL)) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s: invalid param returning PCH_INVALIDPARAM\n", __func__);
+ return PCH_INVALIDPARAM;
+ }
+
+ /* Is interrupt mode of processing is enabled? */
+ if (pch_tt_cbptr != NULL) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s:returning PCH_INTERRUPTMODEINUSE\n", __func__);
+ return PCH_INTERRUPTMODEINUSE;
+ }
+
+ /* Is the System Time reached or exceeded Target Time? */
+ *ttm_poll_flag = pch_ttm_evt_get(pch_pdata);
+ if (!*ttm_poll_flag) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:target time not reached\n", __func__);
+ /* Target Time not to be returned yet */
+ target_tim->tim_val_low_word = 0;
+ target_tim->tim_val_high_word = 0;
+
+ return 0;
+ }
+
+ dev_dbg(&pch_pdata->pdev->dev, "%s:target time reached\n", __func__);
+ /* Get the Target Time */
+ spin_lock_irqsave(&pch_pdata->lock, flags);/*need*/
+ pch_tgt_snap_get(&target_tim->tim_val_low_word,
+ &target_tim->tim_val_high_word, pch_pdata);
+ spin_unlock_irqrestore(&pch_pdata->lock, flags);
+
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:target time:low=%x high=%x\n", __func__,
+ target_tim->tim_val_low_word, target_tim->tim_val_high_word);
+
+ /* Clear the target time reached condition (ttipend bit) */
+ pch_ttm_evt_clear(pch_pdata);
+
+ return 0;
+}
+
+/**
+ * pch_target_time_set() - Sets the Target Time in the IEEE 1588 hardware
+ * assist block
+ * @target_tim: Target time to set.
+ */
+static enum pch_status pch_target_time_set(struct pch_tim_val target_tim,
+ struct pch_dev *chip)
+{
+ unsigned long flags;
+ u32 old_mask = FALSE;
+
+ /* Retrieve existing target time interrupt mask value */
+ old_mask = pch_ttm_imask_get(chip);
+
+ /*
+ * Clear the target time interrupt mask so that the interrupt will not
+ * come
+ * during the time we manipulate the registers.
+ */
+ pch_ttm_imask_clear(chip);
+
+ /* Update Target Time with user specified values */
+ spin_lock_irqsave(&chip->lock, flags);/*need*/
+ pch_tgt_snap_set(target_tim.tim_val_low_word,
+ target_tim.tim_val_high_word, chip);
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ /*
+ * Let the hardware assist re-evaluate the target time reached
+ * condition based on the new target time
+ */
+ pch_ttm_evt_clear(chip);
+
+ /* Restore the preserved target time interrupt mask value */
+ if (old_mask == TRUE)
+ pch_ttm_imask_set(chip);
+
+ return 0;
+}
+
+/**
+ * pch_target_time_get() - Gets the Target Time in the IEEE 1588 hardware
+ * assist block
+ * @target_tim: Address to which target time is to be returned.
+ */
+static enum pch_status pch_target_time_get(struct pch_tim_val *target_tim,
+ struct pch_dev *chip)
+{
+ unsigned long flags;
+ /* Verify the parameter */
+ if (target_tim == (struct pch_tim_val *) NULL)
+ return PCH_INVALIDPARAM;
+
+ /* Get Target Time */
+ spin_lock_irqsave(&chip->lock, flags);/*need*/
+ pch_tgt_snap_get(&target_tim->tim_val_low_word,
+ &target_tim->tim_val_high_word, chip);
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ return 0;
+}
+
+/**
+ * pch_aux_time_interrupt_enable() - Enables the interrupt for the
+ * Auxiliary Master/Slave mode for Time
+ * Stamp in the IEEE 1588 hardware assist
+ * block
+ * @auxmode: Auxiliary slave or master mode.
+ * @callBack: Callback to be invoked when interrupt fires.
+ */
+
+static enum pch_status
+pch_aux_time_interrupt_enable(enum pch_auxmode auxmode,
+ void (*callBack) (enum pch_auxmode,
+ struct pch_tim_val, struct pch_dev *),
+ struct pch_dev *pch_pdata)
+{
+ /* Verify the parameters */
+ if ((PCH_AUXMODE_INVALID <= auxmode) || (callBack == NULL)) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s:invalid param returning PCH_INVALIDPARAM\n", __func__);
+ return PCH_INVALIDPARAM;
+ }
+
+ /* Register the Callback and SET the amm/asm bits on */
+ if (auxmode == PCH_AUXMODE_MASTER) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PCH_AUXMODE_MASTER invoking pch_amms_imask_set\n",
+ __func__);
+ pch_am_cbptr = callBack;
+ pch_amms_imask_set(pch_pdata);
+
+ } else {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PCH_AUXMODE_SLAVE invoking pch_asms_imask_set\n", __func__);
+ pch_as_cbptr = callBack;
+ pch_asms_imask_set(pch_pdata);
+ }
+
+ return 0;
+}
+
+/**
+ * pch_aux_time_interrupt_disable() - Disables the interrupt
+ * @auxmode: uxiliary slave or master mode.
+ *
+ * Disables the interrupt for the Auxiliary Master/Slave mode for Time Stamp in
+ * the IEEE 1588 hardware assist block.
+ */
+static enum pch_status pch_aux_time_interrupt_disable
+ (enum pch_auxmode auxmode, struct pch_dev *pch_pdata)
+{
+ /* Verify the parameters */
+ if (PCH_AUXMODE_INVALID <= auxmode) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s:invalid param returning PCH_INVALIDPARAM\n", __func__);
+ return PCH_INVALIDPARAM;
+ }
+
+ if (auxmode == PCH_AUXMODE_MASTER) {
+ dev_dbg(&pch_pdata->pdev->dev, "%s: PCH_AUXMODE_MASTER invoking"
+ " pch_amms_imask_clear\n", __func__);
+ pch_amms_imask_clear(pch_pdata);
+ pch_am_cbptr = NULL;
+ } else {
+ dev_dbg(&pch_pdata->pdev->dev, "%s:PCH_AUXMODE_SLAVE invoking"
+ " pch_asms_imask_clear\n", __func__);
+ pch_asms_imask_clear(pch_pdata);
+ pch_as_cbptr = NULL;
+ }
+
+ return 0;
+}
+
+/**
+ * pch_aux_time_poll() - Poll for the Auxiliary Time Stamp captured event
+ * for the mode requested
+ * @auxmode: Auxiliary Snapshot Register(Master/Slave) to be checked.
+ * @poll_flag: TRUE if time stamp captured in aux snapshot register.
+ * @auxtime: Buffer for returning captured Auxiliary Snapshot time.
+ *
+ * Polls for the Time stamp in the appropriate Auxiliary Snapshot Registers
+ * based on the mode specified. Return true and the contents of the Auxiliary
+ * snapshot if it is available otherwise return false.
+ */
+
+static enum pch_status
+pch_aux_time_poll(enum pch_auxmode auxmode, u32 *poll_flag,
+ struct pch_tim_val *auxtime, struct pch_dev *pch_pdata)
+{
+ u32 amms_flag = FALSE;
+ u32 asms_flag = FALSE;
+
+ /* Verify the parameters */
+ if ((poll_flag == (u32 *)NULL) ||
+ (PCH_AUXMODE_INVALID <= auxmode) ||
+ (auxtime == (struct pch_tim_val *) NULL)) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invalid param returning PCH_INVALIDPARAM\n", __func__);
+ return PCH_INVALIDPARAM;
+ }
+
+ /* Get Auxiliary Master/Slave Mode Snapshot */
+ if (auxmode == PCH_AUXMODE_MASTER) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PCH_AUXMODE_MASTER\n", __func__);
+ /* Is interrupt mode of processing is enabled? */
+ if (pch_am_cbptr != NULL) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:interrupt mode in use\n", __func__);
+ return PCH_INTERRUPTMODEINUSE;
+ }
+
+ /* Is the Auxiliary Master Mode Snapshot available? */
+ amms_flag = pch_amms_evt_get(pch_pdata);
+ if (!amms_flag) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:NO Auxiliary Master Mode Snapshot available\n",
+ __func__);
+ *poll_flag = FALSE;
+ auxtime->tim_val_low_word = 0;
+ auxtime->tim_val_high_word = 0;
+ return 0;
+ }
+
+ /* Get Auxiliary Master Snapshot */
+ pch_aux_master_snap_get(&auxtime->tim_val_low_word,
+ &auxtime->tim_val_high_word, pch_pdata);
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:Auxiliary Master Snapshot low=%x,high=%x\n",
+ __func__, auxtime->tim_val_low_word,
+ auxtime->tim_val_high_word);
+
+ *poll_flag = TRUE;
+
+ pch_amms_evt_clear(pch_pdata);
+ } else { /* PCH_AUXMODE_SLAVE == auxmode */
+
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PCH_AUXMODE_SLAVE\n", __func__);
+ /* Is interrupt mode of processing is enabled? */
+ if (pch_as_cbptr != NULL) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:interrupt mode in use\n", __func__);
+ return PCH_INTERRUPTMODEINUSE;
+ }
+
+ /* Is the Auxiliary Slave Mode Snapshot available? */
+ asms_flag = pch_asms_evt_get(pch_pdata);
+ if (!asms_flag) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:NO Auxiliary Slave Mode Snapshot available\n",
+ __func__);
+ *poll_flag = FALSE;
+ auxtime->tim_val_low_word = 0;
+ auxtime->tim_val_high_word = 0;
+ return 0;
+ }
+
+ /* Get Auxiliary Slave Snapshot */
+
+ pch_aux_slave_snap_get(&auxtime->tim_val_low_word,
+ &auxtime->tim_val_high_word, pch_pdata);
+
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:Auxiliary Slave Snapshot low=%x,high=%x\n",
+ __func__, auxtime->tim_val_low_word,
+ auxtime->tim_val_high_word);
+
+ *poll_flag = TRUE;
+
+ /* Clear the snapshot availability condition */
+ pch_asms_evt_clear(pch_pdata);
+ }
+
+ return 0;
+}
+
+/* This function enables all 64 bits in system time registers [high & low].
+This is a work-around for non continuous value in the SystemTime Register*/
+static void pch_set_system_time_count(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ PCH_REG_32_WRITE((p + 0xC0), 0x1);
+ PCH_REG_32_WRITE((p + 0xC4), 0xFFFFFFFF);
+ PCH_REG_32_WRITE((p + 0xC0), 0x0);
+}
+
+static enum pch_status pch_reset(struct pch_dev *chip)
+{
+ /* Reset Hardware Assist */
+ pch_block_reset(chip);
+
+ /* Clear Stats */
+ pch_stats.rxmsgs = 0;
+ pch_stats.txmsgs = 0;
+
+ /* Unregister any Callback Routines */
+ pch_pps_cbptr = NULL;
+ pch_tt_cbptr = NULL;
+ pch_am_cbptr = NULL;
+ pch_as_cbptr = NULL;
+
+ /* enable all 32 bits in system time registers */
+ pch_set_system_time_count(chip);
+
+ return 0;
+}
+
+/**
+ * pch_stats_get() - Returns the pch1588 Statistics
+ * @stats: Buffer for returning the statistics counter values.
+ */
+static enum pch_status pch_stats_get(struct pch_stats *stats)
+{
+ /* Verify the parameter */
+ if (stats == (struct pch_stats *) NULL)
+ return PCH_INVALIDPARAM;
+
+
+ /* Return the statistics */
+ stats->rxmsgs = pch_stats.rxmsgs;
+ stats->txmsgs = pch_stats.txmsgs;
+
+ return 0;
+}
+
+static void pch_stats_reset(void)
+{
+ /* Clear the statistics */
+ pch_stats.rxmsgs = 0;
+ pch_stats.txmsgs = 0;
+
+ return;
+}
+
+static void pch_save_state(struct pci_dev *pdev)
+{
+ s32 i;
+ u32 val;
+ struct pch_dev *chip = pci_get_drvdata(pdev);
+ unsigned long flags;
+
+ /* Time stamp control register */
+ pch_regs.ts_control =
+ (pch_ttm_imask_get(chip) << PCH_TSC_TTM_SHIFT) |
+ (pch_asms_imask_get(chip) << PCH_TSC_ASMS_SHIFT) |
+ (pch_amms_imask_get(chip) << PCH_TSC_AMMS_SHIFT) |
+ (pch_pps_imask_get(chip) << PCH_TSC_PPSM_SHIFT);
+ dev_dbg(&pdev->dev,
+ "%s:TS_CONTROL reg=%x\n", __func__, pch_regs.ts_control);
+
+ /*
+ * Time stamp event register; clear on write,
+ * so no point in reading and then saving;
+ * Will be cleared on restore to start in a clean slate
+ */
+ pch_regs.ts_event = PCH_TSE_TTIPEND | PCH_TSE_SNS |
+ PCH_TSE_SNM | PCH_TSE_PPS;
+ dev_dbg(&pdev->dev,
+ "%s:TS_EVENT reg=%x\n", __func__, pch_regs.ts_event);
+
+ /* Addend register */
+ pch_addend_get(&pch_regs.ts_addend, chip);
+ dev_dbg(&pdev->dev,
+ "%s:TS_ADDEND reg=%x\n", __func__, pch_regs.ts_addend);
+
+ /* PPS comapre register */
+ pch_pps_get(&pch_regs.ts_compare, chip);
+ dev_dbg(&pdev->dev,
+ "%s:TS_COMPARE reg=%x\n", __func__, pch_regs.ts_compare);
+
+ /* System time Low and Hi registers */
+ pch_sys_snap_get(&pch_regs.ts_syslo, &pch_regs.ts_syshi, chip);
+ dev_dbg(&pdev->dev,
+ "%s:sys time reg-low =%x,high=%x\n",
+ __func__, pch_regs.ts_syslo, pch_regs.ts_syshi);
+
+ /* Target time Low and Hi registers */
+ spin_lock_irqsave(&chip->lock, flags);/*need*/
+ pch_tgt_snap_get(&pch_regs.ts_tgtlo, &pch_regs.ts_tgthi, chip);
+ spin_unlock_irqrestore(&chip->lock, flags);
+ dev_dbg(&pdev->dev, "%s:target time reg-low =%x,high=%x\n",
+ __func__, pch_regs.ts_tgtlo, pch_regs.ts_tgthi);
+
+#if 0
+ /*
+ * Below registers are read only, so no point in reading/storing, since
+ * we can't restore them
+ */
+ /* Slave mode snapshot Low and Hi registers */
+ pch_aux_slave_snap_get(&pch_regs.ts_asmslo,
+ &pch_regs.ts_asmshi);
+
+ /* Master mode snapshot Low and Hi registers */
+ pch_aux_master_snap_get(&pch_regs.ts_ammslo,
+ &pch_regs.ts_ammshi);
+#endif
+ pch_regs.ts_cc =
+ (pch_master_mode_get(chip) << PCH_CC_MM_SHIFT) |
+ (pch_timestamp_all_get(chip) << PCH_CC_TA_SHIFT) |
+ (pch_op_mode_get(chip) << PCH_CC_MODE_SHIFT) |
+ (pch_version_get(chip) << PCH_CC_VERSION_SHIFT);
+ dev_dbg(&pdev->dev, "%s:TS_CC reg=%x\n", __func__, pch_regs.ts_cc);
+
+ /* Channel event register, not saved - will be cleared on restore */
+ pch_regs.ts_ce = PCH_CE_TXS | PCH_CE_RXS;
+
+#if 0
+ /*
+ * Below registers are read only, so no point in reading/storing, since
+ * we can't restore them
+ */
+ pch_rx_snap_get(&pch_regs.ts_xslo, &pch_regs.ts_xshi);
+ pch_tx_snap_get(&pch_regs.ts_rslo, &pch_regs.ts_rshi);
+ pch_uuid_seqid_get(&pch_regs.ts_uuidlo,
+ &pch_regs.ts_uuidhi);
+
+ /* CAN */
+ pch_can_snap_get(&pch_regs.ts_cxslo, &pch_regs.ts_cxshi);
+#endif
+
+ /* CAN Channel event register, not saved - will be cleared on restore */
+ pch_regs.ts_cce = PCH_CE_OVR | PCH_CE_VAL;
+
+ /* Ethernet CAN selector register */
+ pch_regs.ts_sel =
+ (pch_eth_enable_get(chip) << PCH_ECS_ETH_SHIFT) |
+ (pch_can_enable_get(chip) << PCH_ECS_CAN_SHIFT);
+ dev_dbg(&pdev->dev, "%s:TS_SEL reg=%x\n", __func__, pch_regs.ts_sel);
+
+ /* Station Address registers */
+ for (i = 0; i < PCH_STATION_BYTES; i++) {
+ val = pch_station_get(i, chip);
+ pch_regs.ts_sti[i] = val & 0xff;
+ dev_dbg(&pdev->dev,
+ "%s:TS_ST[%d] reg=%d\n", __func__, i, pch_regs.ts_sti[i]);
+ }
+}
+
+static void pch_restore_state(struct pci_dev *pdev)
+{
+ s32 i;
+ unsigned long flags;
+ struct pch_dev *chip = pci_get_drvdata(pdev);
+
+ /* Time stamp control register */
+ if (pch_regs.ts_control & PCH_TSC_TTM_MASK) {
+ dev_dbg(&pdev->dev,
+ "%s:invoking pch_ttm_imask_set\n", __func__);
+ pch_ttm_imask_set(chip);
+ }
+ if (pch_regs.ts_control & PCH_TSC_ASMS_MASK) {
+ dev_dbg(&pdev->dev,
+ "%s:invoking pch_asms_imask_set\n", __func__);
+ pch_asms_imask_set(chip);
+ }
+ if (pch_regs.ts_control & PCH_TSC_AMMS_MASK) {
+ dev_dbg(&pdev->dev,
+ "%s:invoking pch_amms_imask_set\n", __func__);
+ pch_amms_imask_set(chip);
+ }
+ if (pch_regs.ts_control & PCH_TSC_PPSM_MASK) {
+ dev_dbg(&pdev->dev,
+ "%s:invoking pch_pps_imask_set\n", __func__);
+ pch_pps_imask_set(chip);
+ }
+
+ /* Time stamp event register; clear all events */
+ pch_ttm_evt_clear(chip);
+ pch_asms_evt_clear(chip);
+ pch_amms_evt_clear(chip);
+ pch_pps_evt_clear(chip);
+
+ /* enable all 32 bits in system time registers */
+ pch_set_system_time_count(chip);
+
+ /* Addend register */
+ dev_dbg(&pdev->dev, "%s:invoking pch_addend_set\n", __func__);
+ pch_addend_set(pch_regs.ts_addend, chip);
+
+ /* PPS comapre register */
+ dev_dbg(&pdev->dev, "%s:invoking pch_pps_set\n", __func__);
+ pch_pps_set(pch_regs.ts_compare, chip);
+
+ /* System time Low and Hi registers */
+ dev_dbg(&pdev->dev, "%s:invoking pch_sys_snap_set\n", __func__);
+ pch_sys_snap_set(pch_regs.ts_syslo, pch_regs.ts_syshi, chip);
+
+ /* Target time Low and Hi registers */
+ dev_dbg(&pdev->dev, "%s:invoking pch_tgt_snap_set\n", __func__);
+ spin_lock_irqsave(&chip->lock, flags);/*need*/
+ pch_tgt_snap_set(pch_regs.ts_tgtlo, pch_regs.ts_tgthi, chip);
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ /* Ethernet Channel Control register */
+ if (pch_regs.ts_cc & PCH_CC_MM) {
+ dev_dbg(&pdev->dev,
+ "%s:invoking pch_master_mode_set with TRUE as parameter\n",
+ __func__);
+ pch_master_mode_set(TRUE, chip);
+ }
+ if (pch_regs.ts_cc & PCH_CC_TA) {
+ dev_dbg(&pdev->dev,
+ "%s:invoking pch_timestamp_all_set with TRUE as parameter\n",
+ __func__);
+ pch_timestamp_all_set(TRUE, chip);
+ }
+ dev_dbg(&pdev->dev, "%s:invoking pch_op_mode_set\n", __func__);
+ pch_op_mode_set((pch_regs.ts_cc & PCH_CC_MODE_MASK) >>
+ PCH_CC_MODE_SHIFT, chip);
+ if (pch_regs.ts_cc & PCH_CC_VERSION) {
+ dev_dbg(&pdev->dev,
+ "%s:invoking pch_version_set with PCH_1588PTP_VERSION_1"
+ " as parameter\n", __func__);
+ pch_version_set(PCH_1588PTP_VERSION_1, chip);
+ }
+
+ /* Channel event register, cleared on restore */
+ dev_dbg(&pdev->dev, "%s:invoking pch_rx_snap_evt_clear\n", __func__);
+ pch_rx_snap_evt_clear(chip);
+ dev_dbg(&pdev->dev, "%s:invoking pch_tx_snap_evt_clear\n", __func__);
+ pch_tx_snap_evt_clear(chip);
+
+ /* CAN Channel event register, cleared on restore */
+ dev_dbg(&pdev->dev, "%s:invoking pch_tx_snap_ovr_clear\n", __func__);
+ pch_can_snap_ovr_clear(chip);
+ dev_dbg(&pdev->dev, "%s:invoking pch_tx_snap_valid_clear\n", __func__);
+ pch_can_snap_valid_clear(chip);
+
+ /* Ethernet CAN selector register */
+ if (pch_regs.ts_sel & PCH_ECS_ETH) {
+ dev_dbg(&pdev->dev, "%s:invoking pch_eth_enable_set\n",
+ __func__);
+ pch_eth_enable_set(chip);
+ }
+ if (pch_regs.ts_sel & PCH_ECS_CAN) {
+ dev_dbg(&pdev->dev, "%s:invoking pch_can_enable_set\n",
+ __func__);
+ pch_can_enable_set(chip);
+ }
+
+ /* Station Address registers */
+ for (i = 0; i < PCH_STATION_BYTES; i++) {
+ dev_dbg(&pdev->dev,
+ "%s:invoking pch_station_set for station=%d\n", __func__, i);
+ pch_station_set(i, pch_regs.ts_sti[i], chip);
+ }
+}
+
+static enum pch_status pch_show(struct pch_dev *pch_pdata)
+{
+ s32 i;
+ u32 flag;
+ u32 reg_low;
+ u32 reg_hi;
+ u32 seq_id;
+ u32 uuid_low;
+ u32 uuid_hi;
+ void __iomem *p = pch_pdata->mem_virt;
+ unsigned long flags;
+
+ /* dump all register as such */
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Control Register offset = %x,content = %x\n",
+ PCH_TSC_OFFSET, ioread32(p + PCH_TSC_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Event Register offset = %x,content = %x\n",
+ PCH_TSE_OFFSET, ioread32(p + PCH_TSE_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Addend Register offset = %x,content = %x\n",
+ PCH_ADD_OFFSET, ioread32(p + PCH_ADD_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Accumulator Register offset = %x,content = %x\n",
+ PCH_ACC_OFFSET, ioread32(p + PCH_ACC_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Test Register offset = %x,content = %x\n",
+ PCH_TST_OFFSET, ioread32(p + PCH_TST_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS PPS Compare Register offset = %x,content = %x\n",
+ PCH_PPS_OFFSET, ioread32(p + PCH_PPS_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS System Time Low Register offset = %x,content = %x\n",
+ PCH_STL_OFFSET, ioread32(p + PCH_STL_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS System Time High Register offset = %x,content = %x\n",
+ PCH_STH_OFFSET, ioread32(p + PCH_STH_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Target Time Low Register offset = %x,content = %x\n",
+ PCH_TTL_OFFSET, ioread32(p + PCH_TTL_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Target Time High Register offset = %x,content = %x\n",
+ PCH_TTH_OFFSET, ioread32(p + PCH_TTH_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Aux Slave Mode Snapshot Low Register offset = %x,content = %x\n",
+ PCH_ASSL_OFFSET, ioread32(p + PCH_ASSL_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Aux Slave Mode Snapshot High Register offset = %x,content = %x\n",
+ PCH_ASSH_OFFSET, ioread32(p + PCH_ASSH_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Aux Master Mode Snapshot Low Register offset = %x,content = %x\n",
+ PCH_AMSL_OFFSET, ioread32(p + PCH_AMSL_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Aux Master Mode Snapshot High Register offset = %x,content = %x\n",
+ PCH_AMSH_OFFSET, ioread32(p + PCH_AMSH_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Channel Control Register offset = %x,content = %x\n",
+ PCH_CC_OFFSET, ioread32(p + PCH_CC_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Channel Event Register offset = %x,content = %x\n",
+ PCH_CE_OFFSET, ioread32(p + PCH_CE_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Tx Snapshot High Register offset = %x,content = %x\n",
+ PCH_XSH_OFFSET, ioread32(p + PCH_XSH_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Tx Snapshot Low Register offset = %x,content = %x\n",
+ PCH_XSL_OFFSET, ioread32(p + PCH_XSL_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Rx Snapshot Low Register offset = %x,content = %x\n",
+ PCH_RSL_OFFSET, ioread32(p + PCH_RSL_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Rx Snapshot High Register offset = %x,content = %x\n",
+ PCH_RSH_OFFSET, ioread32(p + PCH_RSH_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Source UUID Low Register offset = %x,content = %x\n",
+ PCH_UID_OFFSET, ioread32(p + PCH_UID_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Source UUID High/SequenceID Register offset = %x,content = %x\n",
+ PCH_SID_OFFSET, ioread32(p + PCH_SID_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS CAN Channel Status Register offset = %x,content = %x\n",
+ PCH_CCE_OFFSET, ioread32(p + PCH_CCE_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS CAN Snapshot Low Register offset = %x,content = %x\n",
+ PCH_CXSL_OFFSET, ioread32(p + PCH_CXSL_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS CAN Snapshot High Register offset = %x,content = %x\n",
+ PCH_CXSH_OFFSET, ioread32(p + PCH_CXSH_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Ethernet/CAN Selecti Register offset = %x,content = %x\n",
+ PCH_ECS_OFFSET, ioread32(p + PCH_ECS_OFFSET));
+ /* Station Address registers */
+ dev_info(&pch_pdata->pdev->dev, "TS Station Address [1-6]");
+ for (i = 0; i < PCH_STATION_BYTES; i++) {
+ reg_low = pch_station_get(i, pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, ":%02x", reg_low);
+ }
+ dev_info(&pch_pdata->pdev->dev, "\n");
+
+ /* Target time reached interrupt mask */
+ flag = pch_ttm_imask_get(pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, "Target Time Interrupt Mask: %s\n",
+ ((flag == TRUE) ? "Set" : "Clear"));
+
+ /* Auxiliary Slave Mode Snapshot interrupt mask */
+ flag = pch_asms_imask_get(pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, "ASMS Interrupt Mask: %s\n",
+ ((flag == TRUE) ? "Set" : "Clear"));
+
+ /* Auxiliary Master Mode Snapshot interrupt mask */
+ flag = pch_amms_imask_get(pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, "AMMS Interrupt Mask: %s\n",
+ ((flag == TRUE) ? "Set" : "Clear"));
+
+ /* Pulse per second interrupt mask */
+ flag = pch_pps_imask_get(pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, "PPS Interrupt Mask: %s\n",
+ ((flag == TRUE) ? "Set" : "Clear"));
+
+ /* TS_Event Register */
+ /* Target time interrupt event */
+ flag = pch_ttm_evt_get(pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, "Target Time Interrupt Pending: %s\n",
+ ((flag == TRUE) ? "Set" : "Clear"));
+
+ /* Auxiliary Slave Mode Snapshot event */
+ flag = pch_asms_evt_get(pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, "ASMS Snapshot Event: %s\n",
+ ((flag == TRUE) ? "Set" : "Clear"));
+
+ /* Auxiliary Master Mode Snapshot event */
+ flag = pch_amms_evt_get(pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, "AMMS Snapshot Event: %s\n",
+ ((flag == TRUE) ? "Set" : "Clear"));
+
+ /* PPS Match event */
+ flag = pch_pps_evt_get(pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, "PPS Match Event: %s\n",
+ ((flag == TRUE) ? "Set" : "Clear"));
+
+ /* Addend Register */
+ reg_low = 0;
+ pch_addend_get(&reg_low, pch_pdata);
+ dev_info(&pch_pdata->pdev->dev,
+ "Frequency Scaling Value: %x\n", reg_low);
+
+ /* PPS Comapre Register */
+ reg_low = 0;
+ pch_pps_get(&reg_low, pch_pdata);
+ dev_info(&pch_pdata->pdev->dev,
+ "PPS Compare Register Value: %x\n", reg_low);
+
+ /* System Time registers */
+ reg_low = reg_hi = 0;
+ pch_sys_snap_get(&reg_low, &reg_hi, pch_pdata);
+
+ dev_info(&pch_pdata->pdev->dev,
+ "System Time (Hi:Low): %x : %x\n", reg_hi, reg_low);
+
+ /* Target Time registers */
+ reg_low = reg_hi = 0;
+ spin_lock_irqsave(&pch_pdata->lock, flags);/*need*/
+ pch_tgt_snap_get(&reg_low, &reg_hi, pch_pdata);
+ spin_unlock_irqrestore(&pch_pdata->lock, flags);
+
+ dev_info(&pch_pdata->pdev->dev,
+ "Target Time (Hi:Low): %x : %x\n", reg_hi, reg_low);
+
+ /* Auxiliary Slave Mode Snapshot registers */
+ reg_low = reg_hi = 0;
+ pch_aux_slave_snap_get(&reg_low, &reg_hi, pch_pdata);
+
+ dev_info(&pch_pdata->pdev->dev,
+ "Auxiliary Slave Mode Snapshot (Hi:Low) : %x : %x\n",
+ reg_hi, reg_low);
+
+ /* Auxiliary Master Mode Snapshot registers */
+ reg_low = reg_hi = 0;
+ pch_aux_master_snap_get(&reg_low, &reg_hi, pch_pdata);
+
+ dev_info(&pch_pdata->pdev->dev,
+ "Auxiliary Master Mode Snapshot (Hi:Low): %x : %x\n",
+ reg_hi, reg_low);
+
+ /* Ethernet port */
+ dev_info(&pch_pdata->pdev->dev, "\nPTP Eth Port\n");
+
+ /* Master Mode */
+ flag = pch_master_mode_get(pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, "Master Mode: %s\n",
+ ((flag == TRUE) ? "Set" : "Clear"));
+
+ /* Timestamp All PTP messages */
+ flag = pch_timestamp_all_get(pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, "Timestamp All Messages: %s\n",
+ ((flag == TRUE) ? "Set" : "Clear"));
+
+ /* Version */
+ flag = pch_version_get(pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, "Version support: %s\n",
+ ((flag == TRUE) ? "v1 and v2" : "v1 only"));
+
+ /* Receive Snapshot Locked */
+ flag = pch_rx_snap_evt(pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, "Receive Snapshot Locked: %s\n",
+ ((flag == TRUE) ? "Set" : "Clear"));
+
+ /* Transmit Snapshot Locked */
+ flag = pch_tx_snap_evt(pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, "Transmit Snapshot Locked: %s\n",
+ ((flag == TRUE) ? "Set" : "Clear"));
+
+ /* Receive Snapshot registers */
+ reg_low = reg_hi = 0;
+ pch_rx_snap_get(&reg_low, &reg_hi, pch_pdata);
+ dev_info(&pch_pdata->pdev->dev,
+ "Receive Snapshot (Hi:Low): %x : %x\n", reg_hi, reg_low);
+
+ /* Transmit Snapshot registers */
+ reg_low = reg_hi = 0;
+ pch_tx_snap_get(&reg_low, &reg_hi, pch_pdata);
+ dev_info(&pch_pdata->pdev->dev,
+ "Transmit Snapshot (Hi:Low): %x : %x\n", reg_hi, reg_low);
+
+ /* UUID and Seqquence Id */
+ pch_uuid_seqid_get(&uuid_low, &uuid_hi, &seq_id, pch_pdata);
+ dev_info(&pch_pdata->pdev->dev,
+ "UUID (Hi:Lo): %x : %x\n", uuid_hi, uuid_low);
+ dev_info(&pch_pdata->pdev->dev, "Sequence id: %x\n", seq_id);
+
+ /* CAN port */
+ dev_info(&pch_pdata->pdev->dev, "\nPTP CAN Port:\n");
+
+ /* Snapshot Valid */
+ flag = pch_can_snap_valid(pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, "Snapshot Valid : %s\n",
+ ((flag == TRUE) ? "Set" : "Clear"));
+
+ /* Snapshot Overrun */
+ flag = pch_can_snap_ovr(pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, "Snapshot Overrun: %s\n",
+ ((flag == TRUE) ? "Set" : "Clear"));
+
+ /* CAN Snapshot registers */
+ reg_low = reg_hi = 0;
+ pch_can_snap_get(&reg_low, &reg_hi, pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, "CAN Snapshot (Hi:Low): %x : %x\n",
+ reg_hi, reg_low);
+
+ /* Ethernet Selector */
+ flag = pch_eth_enable_get(pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, "\nEthernet Enable: %s\n",
+ ((flag == TRUE) ? "Set" : "Clear"));
+
+ /* CAN Selector */
+ flag = pch_can_enable_get(pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, "CAN Enable: %s\n",
+ ((flag == TRUE) ? "Set" : "Clear"));
+
+ /* Station Address Registers */
+ dev_info(&pch_pdata->pdev->dev, "Station Address [1-6]");
+ for (i = 0; i < PCH_STATION_BYTES; i++) {
+ reg_low = pch_station_get(i, pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, ":%02x", reg_low);
+ }
+ dev_info(&pch_pdata->pdev->dev, "\n");
+
+ /* Statistics */
+ dev_info(&pch_pdata->pdev->dev,
+ "Receive Snapshot Count: %u\nTransmit Snapshot Count: %u\n",
+ pch_stats.rxmsgs, pch_stats.txmsgs);
+
+ return 0;
+}
+
+/**
+ * pch_ptp_can_poll() - Polls the IEEE 1588 message time stamp detect
+ * status on a given CAN PTP Port
+ * @ptpport: PTP port to poll.
+ * @ptptimestamp: Buffer to store the snapshot captured.
+ *
+ * This API polls for the availability of a time stamp on a CAN port.
+ */
+static enum pch_status pch_ptp_can_poll(enum pch_ptpport ptpport,
+ struct pch_tim_val *ptptimestamp,
+ struct pch_dev *pch_pdata)
+{
+ u32 valid = FALSE;
+ u32 overrun = FALSE;
+
+ /* Verify the parameters for proper values */
+ if ((ptpport != PCH_CAN_0_1588PTP_PORT) ||
+ (ptptimestamp == (struct pch_tim_val *) NULL)) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invalid params returning PCH_INVALIDPARAM\n", __func__);
+ return PCH_INVALIDPARAM;
+ }
+
+ /* Check whether a new timestamp available? */
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking pch_can_snap_valid\n", __func__);
+ valid = pch_can_snap_valid(pch_pdata);
+
+ /* there is not a valid timestamp */
+ if (valid != TRUE) {
+ dev_dbg(&pch_pdata->pdev->dev, "%s:no valid timestamp "
+ "returning PCH_NOTIMESTAMP\n", __func__);
+ return PCH_NOTIMESTAMP;
+ }
+
+ /* check overrun bit before retreiving timestamp */
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking pch_can_snap_ovr\n", __func__);
+ overrun = pch_can_snap_ovr(pch_pdata);
+
+ /* if the timestamp has been overwritten */
+ if (overrun) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:overrun occured\n", __func__);
+ /* reset valid and overrun bits */
+ pch_can_snap_valid_clear(pch_pdata);
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking pch_can_snap_ovr_clear\n", __func__);
+ pch_can_snap_ovr_clear(pch_pdata);
+
+ /* return no valid timestamp available */
+ ptptimestamp->tim_val_low_word = 0;
+ ptptimestamp->tim_val_high_word = 0;
+
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:returning PCH_NOTIMESTAMP\n", __func__);
+ return PCH_NOTIMESTAMP;
+ }
+
+ /* Fetch the receive timestamp */
+
+ pch_can_snap_get(&ptptimestamp->tim_val_low_word,
+ &ptptimestamp->tim_val_high_word, pch_pdata);
+ dev_dbg(&pch_pdata->pdev->dev, "%s:timestamp-low=%x,high=%x\n",
+ __func__, ptptimestamp->tim_val_low_word,
+ ptptimestamp->tim_val_high_word);
+
+ /* check overrun bit again to ensure timestamp is valid */
+ overrun = pch_can_snap_ovr(pch_pdata);
+
+ /* if the timestamp has been overwritten */
+ if (overrun) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:overrun occured\n", __func__);
+ /* reset valid and overrun bits */
+ pch_can_snap_valid_clear(pch_pdata);
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking pch_can_snap_ovr_clear\n", __func__);
+ pch_can_snap_ovr_clear(pch_pdata);
+
+ /* return no valid timestamp available */
+ ptptimestamp->tim_val_low_word = 0;
+ ptptimestamp->tim_val_high_word = 0;
+
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:returning PCH_NOTIMESTAMP\n", __func__);
+ return PCH_NOTIMESTAMP;
+ }
+
+ /* reset valid bit */
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking pch_can_snap_valid_clear\n", __func__);
+ pch_can_snap_valid_clear(pch_pdata);
+
+ return 0;
+}
+
+static enum pch_status pch_handler(struct pch_dev *pch_pdata)
+{
+ struct pch_tim_val tgt_time = { 0, 0 };
+ struct pch_tim_val aux_time = { 0, 0 };
+ u32 pps;
+
+ /* If valid callbacks are available process each interrupt */
+
+ /* Handle Target Time Reached or Exceeded Interrupt */
+ if ((pch_tt_cbptr != NULL) && (pch_ttm_evt_get(pch_pdata) == TRUE)) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:Target Time Reached or Exceeded Interrupt\n", __func__);
+ /* Disable interrupt */
+ pch_ttm_imask_clear(pch_pdata);
+
+ /* Target Time registers contents */
+ spin_lock(&pch_pdata->lock);/*need*/
+ pch_tgt_snap_get(&tgt_time.tim_val_low_word,
+ &tgt_time.tim_val_high_word, pch_pdata);
+ spin_unlock(&pch_pdata->lock);
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:target time-low=%x,high=%x\n",
+ __func__, tgt_time.tim_val_low_word,
+ tgt_time.tim_val_high_word);
+
+ /* Invoke client callback */
+ (*pch_tt_cbptr) (tgt_time, pch_pdata);
+
+ /* Clear the target time reached condition (ttipend bit) */
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking pch_ttm_evt_clear\n", __func__);
+ pch_ttm_evt_clear(pch_pdata);
+ }
+
+ /* Handle Auxiliary Master Mode Snapshot Interrupt */
+ if ((pch_am_cbptr != NULL) && (pch_amms_evt_get(pch_pdata) == TRUE)) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:Auxiliary Master Mode Snapshot Interrupt\n", __func__);
+ /* Disable interrupt */
+ pch_amms_imask_clear(pch_pdata);
+
+ /* Fetch Auxiliary Master Mode Snapshot */
+ spin_lock(&pch_pdata->lock);
+ pch_aux_master_snap_get(&aux_time.tim_val_low_word,
+ &aux_time.tim_val_high_word, pch_pdata);
+ spin_unlock(&pch_pdata->lock);
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:Auxiliary Master Mode Snapshot-low=%x,high=%x\n",
+ __func__, aux_time.tim_val_low_word,
+ aux_time.tim_val_high_word);
+
+ /* Return Auxiliary Master Mode Snapshot */
+ (*pch_am_cbptr) (PCH_AUXMODE_MASTER, aux_time, pch_pdata);
+
+ /* Clear the snapshot availability condition */
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking pch_amms_evt_clear\n", __func__);
+ pch_amms_evt_clear(pch_pdata);
+ }
+
+ /* Handle Auxiliary Slave Mode Snapshot Interrupt */
+ if ((pch_as_cbptr != NULL) && (pch_asms_evt_get(pch_pdata) == TRUE)) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:Auxiliary Slave Mode Snapshot Interrupt\n", __func__);
+ /* Disable interrupt */
+ pch_asms_imask_clear(pch_pdata);
+
+ /* Fetch Auxiliary Slave Mode Snapshot */
+ spin_lock(&pch_pdata->lock);
+ pch_aux_slave_snap_get(&aux_time.tim_val_low_word,
+ &aux_time.tim_val_high_word, pch_pdata);
+ spin_unlock(&pch_pdata->lock);
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:Auxiliary Master Mode Snapshot-low=%x, high=%x\n",
+ __func__, aux_time.tim_val_low_word,
+ aux_time.tim_val_high_word);
+
+ /* Return Auxiliary Slave Mode Snapshot */
+ (*pch_as_cbptr) (PCH_AUXMODE_SLAVE, aux_time, pch_pdata);
+
+ /* Clear the snapshot availability condition */
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking pch_asms_evt_clear\n", __func__);
+ pch_asms_evt_clear(pch_pdata);
+ }
+
+ /* Handle Pulse Per Second Interrupt */
+ if ((pch_pps_cbptr != NULL) && (pch_pps_evt_get(pch_pdata) == TRUE)) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:Pulse Per Second Interrupt\n", __func__);
+ /* Disable interrupt */
+ pch_pps_imask_clear(pch_pdata);
+
+ /* Fetch PPS compare register */
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking pch_pps_get\n", __func__);
+ pch_pps_get(&pps, pch_pdata);
+
+ /* Invoke the call back */
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking callback\n", __func__);
+ (*pch_pps_cbptr) (pps, pch_pdata);
+
+ /* Clear the snapshot availability condition */
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking pch_pps_evt_clear\n", __func__);
+ pch_pps_evt_clear(pch_pdata);
+
+ }
+
+ return 0;
+}
+
+/**
+ * pch_ptp_version_get() - Retrieves IEEE 1588 PTP version supported on the
+ * given PTP port
+ * @ptpport: PTP port.
+ * @ptpversion: Version supported on PTP port.
+ */
+static enum pch_status pch_ptp_version_get(enum pch_ptpport ptpport,
+ enum pch_ptpversion *ptpversion,
+ struct pch_dev *chip)
+{
+ /* Verify the parameters for proper values */
+ if ((ptpport != PCH_GBE_0_1588PTP_PORT) || (ptpversion == NULL))
+ return PCH_INVALIDPARAM;
+
+ *ptpversion = pch_version_get(chip);
+
+ return 0;
+}
+
+/**
+ * pch_ptp_version_set() - Configures IEEE 1588 PTP version to be used on
+ * given PTP port
+ * @ptpport: PTP port.
+ * @ptpversion: Version to be supported on PTP port.
+ */
+static enum pch_status pch_ptp_version_set(enum pch_ptpport ptpport,
+ enum pch_ptpversion ptpversion,
+ struct pch_dev *chip)
+{
+ /* Verify the parameters for proper values */
+ if ((ptpport != PCH_GBE_0_1588PTP_PORT) ||
+ ((ptpversion != PCH_1588PTP_VERSION_0) &&
+ (ptpversion != PCH_1588PTP_VERSION_1))) {
+ return PCH_INVALIDPARAM;
+ }
+
+ pch_version_set(ptpversion, chip);
+
+ return 0;
+}
+
+/**
+ * pch_ptp_operation_mode_set() - Configure the IEEE 1588 PTP operation
+ * mode of given PTP port
+ * @ptpport: PTP port to configure.
+ * @ptpMode: Operation mode to be used.
+ */
+static enum pch_status pch_ptp_operation_mode_set(enum pch_ptpport ptpport,
+ enum pch_ptpope_mode ptp_mode,
+ struct pch_dev *chip)
+{
+ /* Verify the parameters for proper values */
+ if ((ptpport != PCH_GBE_0_1588PTP_PORT) ||
+ ((ptp_mode != PCH_1588PTP_OP_MODE_SYNC_DELAYREQ_MSGS) &&
+ (ptp_mode != PCH_1588PTP_OP_MODE_V1_ALL_MSGS) &&
+ (ptp_mode != PCH_1588PTP_OP_MODE_V1_V2_EVENT_MSGS) &&
+ (ptp_mode != PCH_1588PTP_OP_MODE_V1_V2_ALL_MSGS))) {
+ return PCH_INVALIDPARAM;
+ }
+
+ pch_op_mode_set(ptp_mode, chip);
+ return 0;
+}
+
+/**
+ * pch_ptp_operation_mode_get() - ets the current PTP operation mode of
+ * given PTP port
+ * @ptpport: PTP port to configure.
+ * @ptp_mode: Address where PTP operation mode is returned.
+ */
+static enum pch_status pch_ptp_operation_mode_get
+ (enum pch_ptpport ptpport, enum pch_ptpope_mode *ptp_mode,
+ struct pch_dev *chip)
+{
+ /* Verify the parameters for proper values */
+ if ((ptpport != PCH_GBE_0_1588PTP_PORT) || (ptp_mode == NULL))
+ return PCH_INVALIDPARAM;
+
+ *ptp_mode = pch_op_mode_get(chip);
+
+ return 0;
+}
+
+/**
+ * pch_pulse_per_sec_interrupt_enable() - Enable the Pulse Per Second match
+ * interrupt
+ * @callBack: Routine to be invoked when interrupt fires.
+ *
+ * This API will enable the Pulse Per Second match interrupt.This interrupt is
+ * generated when the low word of System Time matches the value in the Pulse Per
+ * Second compare register in the IEEE hardware assist block.
+ */
+static enum pch_status pch_pulse_per_sec_interrupt_enable
+ (void (*callBack) (u32, struct pch_dev *), struct pch_dev *chip)
+{
+ /* Verify the parameter */
+ if (callBack == NULL)
+ return PCH_INVALIDPARAM;
+
+ /* Register the Callback */
+ pch_pps_cbptr = callBack;
+
+ /* Set target time interrupt mask */
+ pch_pps_imask_set(chip);
+
+ return 0;
+}
+
+static enum pch_status pch_pulse_per_sec_interrupt_disable(struct pch_dev *chip)
+{
+ /* Clear pulse per second interrupt mask */
+ pch_pps_imask_clear(chip);
+
+ /* Unregister the Callback */
+ pch_pps_cbptr = NULL;
+
+ return 0;
+}
+
+/**
+ * pch_pulse_per_sec_time_set() - Sets the Pulse Per Second match time in
+ * the IEEE 1588 hardware assist block
+ * @pps_time: Value to be stored in pps match register.
+ */
+static enum pch_status pch_pulse_per_sec_time_set(u32 pps_time,
+ struct pch_dev *chip)
+{
+ u32 old_mask = FALSE;
+
+ /* Retrieve existing pps mask value */
+ old_mask = pch_pps_imask_get(chip);
+
+ /*
+ * Clear the pps time interrupt mask so that the interrupt will not come
+ * during the time we manipulate the registers.
+ */
+ pch_pps_imask_clear(chip);
+
+ /* Update the PPS time */
+ pch_pps_set(pps_time, chip);
+
+ /*
+ * Let the hardware assist re-evaluate the pps reached
+ * condition based on the new pps value
+ */
+ pch_pps_evt_clear(chip);
+
+ /* Restore the preserved pps interrupt mask value */
+ if (old_mask == TRUE)
+ pch_pps_imask_set(chip);
+
+ return 0;
+}
+
+/**
+ * pch_pulse_per_sec_time_get() - Gets the Pulse Per Second match time from
+ * the IEEE 1588 hardware assist block
+ * @pps_time: Buffer for returning the pps match value.
+ * @qq: aa.
+ */
+static enum pch_status pch_pulse_per_sec_time_get(u32 *pps_time,
+ struct pch_dev *chip)
+{
+ /* Verify the parameter */
+ if (pps_time == (u32 *)NULL)
+ return PCH_INVALIDPARAM;
+
+ /* Retrieve PPS Value */
+ pch_pps_get(pps_time, chip);
+
+ return 0;
+}
+
+static enum pch_status pch_eth_enable(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+
+ if (p != 0)
+ pch_eth_enable_set(chip);
+
+ return 0;
+}
+
+static enum pch_status pch_eth_disable(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+
+ if (p != 0)
+ pch_eth_enable_clear(chip);
+
+ return 0;
+}
+
+static enum pch_status pch_can_enable(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+
+ if (p != 0)
+ pch_can_enable_set(chip);
+
+ return 0;
+}
+
+static enum pch_status pch_can_disable(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+
+ if (p != 0)
+ pch_can_enable_clear(chip);
+
+ return 0;
+}
+
+/**
+ * get_decimal() - Returns the decimal value of the passed hexadecimal value
+ * @ch: The hexadecimal value that has to be converted.
+ */
+static s32 get_decimal(u8 ch)
+{
+ s32 ret;
+
+ if ((ch >= '0') && (ch <= '9'))
+ ret = ch - '0';
+ else if ((ch >= 'A') && (ch <= 'F'))
+ ret = 10 + ch - 'A';
+ else if ((ch >= 'a') && (ch <= 'f'))
+ ret = 10 + ch - 'a';
+ else
+ return -1;
+
+ return ret;
+}
+
+/**
+ * pch_set_station_address() - This API sets the station address used by
+ * IEEE 1588 hardware when looking at PTP
+ * traffic on the ethernet interface
+ * @addr: dress which contain the column separated address to be used.
+ */
+static enum pch_status pch_set_station_address(u8 *addr, struct pci_dev *pdev)
+{
+ s32 i;
+ struct pch_dev *chip = pci_get_drvdata(pdev);
+ void __iomem *p = chip->mem_virt;
+
+ /* Verify the parameter */
+ if ((p == 0) || addr == (u8 *)NULL) {
+ dev_err(&pdev->dev,
+ "%s :invalid params returning PCH_INVALIDPARAM\n", __func__);
+ return PCH_INVALIDPARAM;
+ }
+
+ for (i = 0; i < PCH_STATION_BYTES; i++) { /* For all station
+ address bytes */
+ u32 val;
+ s32 tmp;
+
+ tmp = get_decimal(addr[i * 3]);
+ if (tmp < 0) {
+ dev_err(&pdev->dev,
+ "%s :invalid params returning PCH_INVALIDPARAM\n",
+ __func__);
+ return PCH_INVALIDPARAM;
+ }
+ val = tmp * 16;
+ tmp = get_decimal(addr[(i * 3) + 1]);
+ if (tmp < 0) {
+ dev_err(&pdev->dev,
+ "%s :invalid params returning PCH_INVALIDPARAM\n",
+ __func__);
+ return PCH_INVALIDPARAM;
+ }
+ val += tmp;
+ if ((i < 5) && (addr[(i * 3) + 2] != ':')) { /* Expects ':'
+ separated addresses */
+ dev_err(&pdev->dev,
+ "%s :invalid params returning PCH_INVALIDPARAM\n",
+ __func__);
+ return PCH_INVALIDPARAM;
+ }
+
+ /* Ideally we should set the address only after validating
+ entire string */
+ dev_dbg(&pdev->dev, "%s :invoking pch_station_set\n", __func__);
+ pch_station_set(i, val, chip);
+ }
+ return 0;
+}
+
+/**
+ * pch_get_station_address() - This API gets the station address currently
+ * used by IEEE 1588 ardware when looking at
+ * PTP traffic on the ethernet interface
+ * @addr: Buffer to which column separated address is returned.
+ */
+static enum pch_status pch_get_station_address(s8 *addr, struct pch_dev *chip)
+{
+ s32 i;
+
+ /* Verify the parameter */
+ if (addr == (s8 *)NULL)
+ return PCH_INVALIDPARAM;
+
+ for (i = 0; i < PCH_STATION_BYTES; i++) {
+ u32 val = 0;
+
+ val = pch_station_get(i, chip);
+ addr[i * 3] = val / 16;
+ if (addr[i * 3] > 9)
+ addr[i * 3] += 'a' - 10;
+ else
+ addr[i * 3] += '0';
+ addr[i * 3 + 1] = val % 16;
+ if (addr[i * 3 + 1] > 9)
+ addr[i * 3 + 1] += 'a' - 10;
+ else
+ addr[i * 3 + 1] += '0';
+ addr[i * 3 + 2] = ':';
+ }
+ addr[17] = '\0';
+ return 0;
+}
+
+/**
+ * pch_aux_target_time_interrupt_enable() - This API just returns an error
+ * @callBack: Callback to be invoked when interrupt fires.
+ */
+static enum pch_status pch_aux_target_time_interrupt_enable(void *callBack)
+{
+ return PCH_UNSUPPORTED;
+}
+
+static enum pch_status pch_aux_target_time_interrupt_disable(void)
+{
+ return PCH_UNSUPPORTED;
+}
+
+/**
+ * pch_aux_target_time_poll() - This API just returns an error.
+ * @attm_poll_flag: Flag returning the availablity of a snapshot.
+ * @target_tim: Snapshot captured.
+ */
+static enum pch_status pch_aux_target_time_poll(u32 *attm_poll_flag,
+ struct pch_tim_val *target_tim)
+{
+ return PCH_UNSUPPORTED;
+}
+
+/**
+ * pch_aux_target_time_set() - This API just returns an error
+ * @target_tim: Time to set to.
+ */
+static enum pch_status pch_aux_target_time_set(struct pch_tim_val target_tim)
+{
+ return PCH_UNSUPPORTED;
+}
+
+/**
+ * pch_aux_target_time_get() - his API just returns an error
+ * @target_tim: Buffer for returning time snapshot.
+ */
+static enum pch_status pch_aux_target_time_get(struct pch_tim_val *target_tim)
+{
+ return PCH_UNSUPPORTED;
+}
+
+s32 pch_eth_can_get(struct pch_dev *chip)
+{
+ s32 ieee_mode = 0;
+
+ if (pch_eth_enable_get(chip) == 1)
+ ieee_mode |= PCH_IEEE1588_ETH;
+ if (pch_can_enable_get(chip) == 1)
+ ieee_mode |= PCH_IEEE1588_CAN;
+
+ return ieee_mode;
+}
+
+static s32 pch_open(struct inode *inode, struct file *filep)
+{
+ struct pch_dev *pch_dev;
+ s32 ret;
+
+ ret = mutex_lock_interruptible(&pch_1588_mutex);
+ if (ret) {
+ ret = -ERESTARTSYS;
+ goto return_nomutex;
+ }
+ pch_dev = container_of(inode->i_cdev, struct pch_dev, cdev);
+ filep->private_data = pch_dev;
+
+ if (pch_dev->suspend) {
+ dev_err(&pch_dev->pdev->dev,
+ "%s returning as device is suspended\n", __func__);
+ ret = -EBUSY;
+ goto out;
+ }
+ ret = 0;
+out:
+ mutex_unlock(&pch_1588_mutex);
+return_nomutex:
+ return ret;
+}
+
+static s32 pch_release(struct inode *inode, struct file *filep)
+{
+ struct pch_dev *pch_dev;
+
+ pch_dev = container_of(inode->i_cdev, struct pch_dev, cdev);
+
+ dev_info(&pch_dev->pdev->dev, "%s\n", __func__);
+
+ return 0;
+}
+
+/**
+ * ioc_handle_notify() - Handles all NOTIFY IOCTLs
+ * @cmd: the IOCTL command.
+ * @buf: the reference to data to be returned.
+ */
+static s32 ioc_handle_notify(u32 cmd, s8 *buf, struct pch_dev *pch_pdata)
+{
+ u32 bytes_ret;
+ void *param_addr;
+ wait_queue_head_t *event;
+ u32 eventnum;
+
+ if (cmd == IOCTL_1588_AUX_TARG_TIME_NOTIFY) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s returning...[cmd = IOCTL_1588_AUX_TARG_TIME_NOTIFY]\n",
+ __func__);
+ return -EINVAL;
+ }
+ /* request to be notified of a 1588 interrupt event Target Time */
+ else if (cmd == IOCTL_1588_TARG_TIME_NOTIFY) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s cmd = IOCTL_1588_TARG_TIME_NOTIFY]\n", __func__);
+ event = &pch_pdata->notify_evt[TARG_TIME_EVENT_NUM];
+ bytes_ret = sizeof(struct pch_tim_val);
+ param_addr = &pch_target_time;
+ eventnum = TARG_TIME_EVENT_NUM;
+ } else if (cmd == IOCTL_1588_AUX_TIME_NOTIFY) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s cmd = IOCTL_1588_AUX_TIME_NOTIFY]\n", __func__);
+ event = &pch_pdata->notify_evt[AUX_TIME_EVENT_NUM];
+ bytes_ret = sizeof(struct pch_auxtimeioctl);
+ param_addr = &pch_aux_time;
+ eventnum = AUX_TIME_EVENT_NUM;
+ } else {
+ event = &pch_pdata->notify_evt[PPS_EVENT_NUM];
+ bytes_ret = sizeof(u32);
+ param_addr = &pch_pps_time;
+ eventnum = PPS_EVENT_NUM;
+ }
+
+ pch_pdata->event_flags[eventnum] = 0;
+
+ /* wait infinitely for a 1588 interrupt event to occur */
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s waiting for interrupt event...\n", __func__);
+ wait_event_interruptible(*event, pch_pdata->event_flags[eventnum] == 1);
+ dev_dbg(&pch_pdata->pdev->dev, "%s got interrupt event...\n", __func__);
+
+ /* copy global data retreived from interrupt handler */
+ memcpy((void *)&buf, (const void *)param_addr, bytes_ret);
+
+ /* reset global data to 0 */
+ memset((void *)param_addr, 0, bytes_ret);
+
+ pch_pdata->event_flags[eventnum] = 0;
+
+ return 0;
+}
+
+/**
+ * ioc_handle_clr_notify() - andles all CLEAR NOTIFY IOCTLs
+ * @cmd: the IOCTL command.
+ * @buf: unused.
+ */
+static s32 ioc_handle_clr_notify(u32 cmd, s8 *buf, struct pch_dev *pch_pdata)
+{
+ u32 eventnum;
+
+ /*
+ * request to release a notify thread that is waiting
+ * on a 1588 interrupt event
+ */
+ if (cmd == IOCTL_1588_TARG_TIME_CLR_NOTIFY) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s cmd=IOCTL_1588_TARG_TIME_CLR_NOTIFY\n", __func__);
+ eventnum = TARG_TIME_EVENT_NUM;
+ } else if (cmd == IOCTL_1588_AUX_TIME_CLR_NOTIFY) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s cmd=IOCTL_1588_AUX_TIME_CLR_NOTIFY\n", __func__);
+ eventnum = AUX_TIME_EVENT_NUM;
+ } else if (cmd == IOCTL_1588_PULSE_PER_SEC_CLR_NOTIFY) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s cmd=IOCTL_1588_PULSE_PER_SEC_CLR_NOTIFY\n", __func__);
+ eventnum = PPS_EVENT_NUM;
+ } else if (cmd == IOCTL_1588_AUX_TARG_TIME_CLR_NOTIFY) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s cmd=IOCTL_1588_AUX_TARG_TIME_CLR_NOTIFY\n", __func__);
+ dev_err(&pch_pdata->pdev->dev,
+ "%s returning -EINVAL\n", __func__);
+ return -EINVAL;
+ } else {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s : Unknown command returning -EINVAL\n", __func__);
+ return -EINVAL;
+ }
+
+ pch_pdata->event_flags[eventnum] = 1;
+
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s waking up blocking notify call..\n", __func__);
+ wake_up_interruptible(&pch_pdata->notify_evt[eventnum]);
+ return 0;
+}
+
+/**
+ * ioc_handle_reset() - Handles reset and channel reset IOCTLs
+ * @cmd: the IOCTL command.
+ * @buf: unused.
+ */
+static s32 ioc_handle_reset(u32 cmd, s8 *buf, struct pch_dev *pch_pdata)
+{
+ s32 i;
+ s32 ieee_mode;
+ u8 station[STATION_ADDR_LEN] = "00:00:00:00:00:00";
+
+ dev_dbg(&pch_pdata->pdev->dev, "%s: invoking pch_reset\n", __func__);
+
+ /* retrieve eth/CAN mode */
+ ieee_mode = pch_eth_can_get(pch_pdata);
+
+ /* retrieve station address */
+ pch_get_station_address(station, pch_pdata);
+
+ /* reset the 1588 hardware */
+ if (pch_reset(pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s: pch_reset failed\n", __func__);
+ return -EINVAL;
+ }
+ /* Anyway, now clear all the events */
+ for (i = 0; i < NUM_EVENTS; i++)
+ pch_pdata->event_flags[i] = 0;
+ /* set ETH/CAN mode */
+ if (ieee_mode & PCH_IEEE1588_ETH)
+ pch_eth_enable(pch_pdata);
+ if (ieee_mode & PCH_IEEE1588_CAN)
+ pch_can_enable(pch_pdata);
+
+ /* set station address */
+ if (strcmp(station, "00:00:00:00:00:00") != 0) {
+ if (pch_set_station_address(station, pch_pdata->pdev) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_reset: could not set station address\n");
+ }
+ }
+
+ dev_dbg(&pch_pdata->pdev->dev, "%s: returning 0\n", __func__);
+ return 0;
+}
+
+/**
+ * ioc_handle_stats_reset() - Handles reset statistics IOCTLs
+ * @cmd: unused.
+ * @buf: unused.
+ */
+static s32 ioc_handle_stats_reset(u32 cmd, s8 *buf, struct pch_dev *pch_pdata)
+{
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s: invoking pch_stats_reset\n", __func__);
+ pch_stats_reset();
+ dev_dbg(&pch_pdata->pdev->dev, "%s: returning 0\n", __func__);
+ return 0;
+}
+
+/**
+ * ioc_handle_stats() - Handles get statistics IOCTL
+ * @cmd: the IOCTL command.
+ * @buf: reference to statistics retrieved.
+ */
+static s32 ioc_handle_stats(u32 cmd, s8 *buf, struct pch_dev *pch_pdata)
+{
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s: invoking pch_pch_stats_get\n", __func__);
+ if (pch_stats_get((struct pch_stats *) buf) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_stats_get failed\n");
+ return -EINVAL;
+ }
+ dev_dbg(&pch_pdata->pdev->dev, "ioc_handle_statst: returning 0\n");
+ return 0;
+}
+
+/**
+ * ioc_handle_show() - andles show all IOCTL
+ * @cmd: unused.
+ * @buf: unused.
+ */
+static s32 ioc_handle_show(u32 cmd, s8 *buf, struct pch_dev *pch_pdata)
+{
+ dev_dbg(&pch_pdata->pdev->dev, "%s: invoking pch_show\n", __func__);
+ if (pch_show(pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev, "pch_show failed\n");
+ return -EINVAL;
+ }
+ dev_dbg(&pch_pdata->pdev->dev, "%s: returning 0\n", __func__);
+ return 0;
+}
+
+/**
+ * target_time_callback() - The callback function that is called from the HAL
+ * when the target time expired interrupt occurs
+ * @tgt_time: target time register timestamp.
+ */
+static void target_time_callback(struct pch_tim_val tgt_time,
+ struct pch_dev *pch_pdata)
+{
+ /*
+ * copy the target time value to the global value to be read by the
+ * notify ioctl
+ */
+ memcpy((void *)&pch_target_time, (const void *)&tgt_time,
+ sizeof(struct pch_tim_val));
+
+ pch_pdata->event_flags[TARG_TIME_EVENT_NUM] = 1;
+
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s: signalling the notify ioctl that the target time has expired\n",
+ __func__);
+ /* signal the notify ioctl that the target time has expired */
+ wake_up_interruptible(&pch_pdata->notify_evt[TARG_TIME_EVENT_NUM]);
+}
+
+/**
+ * auxiliary_time_callback() - The callback function that is called from the HAL
+ * when an aux time interrupt has occurred
+ * @aux_mode: master, slave, or any.
+ * @aux_time: aux time register timestamp.
+ */
+static void auxiliary_time_callback(enum pch_auxmode aux_mode,
+ struct pch_tim_val aux_time,
+ struct pch_dev *pch_pdata)
+{
+ /*
+ * copy the aux time value and aux mode to the global value
+ * to be read by the notify ioctl
+ */
+
+ pch_aux_time.auxmode = aux_mode;
+ memcpy((void *)&pch_aux_time.auxtime, (const void *)&aux_time,
+ sizeof(struct pch_auxtimeioctl));
+
+ pch_pdata->event_flags[AUX_TIME_EVENT_NUM] = 1;
+
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s: signalling the notify ioctl that the auxiliary time stamp"
+ " has been set\n", __func__);
+
+ /*
+ * signal the notify ioctl that the aux timestamp has been set
+ */
+ wake_up_interruptible(&pch_pdata->notify_evt[AUX_TIME_EVENT_NUM]);
+}
+
+/**
+ * pulse_per_sec_callback() - This is a callback function that will be called
+ * from the HAL when the pulse per second time has
+ * expired which generates an interrupt
+ * @pps: pulse per second register timestamp.
+ */
+static void pulse_per_sec_callback(u32 pps, struct pch_dev *pch_pdata)
+{
+ pch_pps_time = pps;
+
+ pch_pdata->event_flags[PPS_EVENT_NUM] = 1;
+
+ /* signal the notify ioctl that the pulse per second time has expired */
+ wake_up_interruptible(&pch_pdata->notify_evt[PPS_EVENT_NUM]);
+}
+
+/**
+ * ioc_handle_int_enable() - Handles all interrupt enable IOCTLs
+ * @cmd: the IOCTL command.
+ * @buf: he reference to auxiliary mode.
+ */
+static s32 ioc_handle_int_enable(u32 cmd, s8 *buf, struct pch_dev *pch_pdata)
+{
+ s32 ret;
+
+ ret = 0;
+ if (cmd == IOCTL_1588_TARG_TIME_INTRPT_ENABLE) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s cmd=IOCTL_1588_TARG_TIME_INTRPT_ENABLE invoking "
+ "pch_target_time_interrupt_enable\n", __func__);
+ if (pch_target_time_interrupt_enable
+ (target_time_callback, pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_target_time_interrupt_enable failed\n");
+ ret = -EINVAL;
+ }
+ } else if (cmd == IOCTL_1588_AUX_TIME_INTRPT_ENABLE) {
+ enum pch_auxmode aux_mode;
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s cmd=IOCTL_1588_AUX_TIME_INTRPT_ENABLE invoking "
+ "pch_aux_time_interrupt_enable\n", __func__);
+
+ memcpy((void *)&aux_mode, (const void *)buf,
+ sizeof(enum pch_auxmode));
+
+ if (pch_aux_time_interrupt_enable
+ (aux_mode, auxiliary_time_callback, pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_aux_time_interrupt_enable failed\n");
+ ret = -EINVAL;
+ }
+ } else if (cmd == IOCTL_1588_PULSE_PER_SEC_INTRPT_ENABLE) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s cmd=IOCTL_1588_PULSE_PER_SEC_INTRPT_ENABLE invoking "
+ "pch_pulse_per_sec_interrupt_enable\n", __func__);
+ if (pch_pulse_per_sec_interrupt_enable
+ (pulse_per_sec_callback, pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_pps_interrupt_enable failed\n");
+ ret = -EINVAL;
+ }
+ } else { /* IOCTL_1588_AUX_TARG_TIME_INTRPT_ENABLE */
+
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s cmd=OCTL_1588_AUX_TARG_TIME_INTRPT_ENABLE invoking"
+ " pch_aux_target_time_interrupt_enable\n", __func__);
+ if (pch_aux_target_time_interrupt_enable(NULL) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_aux_target_time_interrupt_enable failed\n");
+ ret = -EINVAL;
+ }
+ }
+ return ret;
+}
+
+/**
+ * ioc_handle_int_disable() - Handles all interrupt enable IOCTLs
+ * @cmd: the IOCTL command.
+ * @buf: the reference to auxiliary mode.
+ */
+static s32 ioc_handle_int_disable(u32 cmd, s8 *buf, struct pch_dev *pch_pdata)
+{
+ s32 ret;
+
+ ret = 0;
+ if (cmd == IOCTL_1588_TARG_TIME_INTRPT_DISABLE) {
+ dev_dbg(&pch_pdata->pdev->dev, "%s cmd="
+ "IOCTL_1588_TARG_TIME_INTRPT_DISABLE invoking "
+ "pch_target_time_interrupt_disable\n", __func__);
+ if (pch_target_time_interrupt_disable(pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_target_time_interrupt_disable failed\n");
+ ret = -EINVAL;
+ }
+ } else if (cmd == IOCTL_1588_AUX_TIME_INTRPT_DISABLE) {
+ enum pch_auxmode aux_mode;
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s cmd=IOCTL_1588_AUX_TIME_INTRPT_DISABLE "
+ "invoking pch_aux_time_interrupt_disable\n", __func__);
+
+ memcpy((void *)&aux_mode, (const void *)buf,
+ sizeof(enum pch_auxmode));
+
+ if (pch_aux_time_interrupt_disable(aux_mode, pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_aux_time_interrupt_disable failed\n");
+ ret = -EINVAL;
+ }
+ } else if (cmd == IOCTL_1588_PULSE_PER_SEC_INTRPT_DISABLE) {
+ dev_dbg(&pch_pdata->pdev->dev, "%s cmd="
+ "IOCTL_1588_PULSE_PER_SEC_INTRPT_DISABLE "
+ "invoking pch_pulse_per_sec_interrupt_disable\n", __func__);
+ if (pch_pulse_per_sec_interrupt_disable(pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_pulse_per_sec_interrupt_disable failed\n");
+ ret = -EINVAL;
+ }
+ } else { /* IOCTL_1588_AUX_TARG_TIME_INTRPT_DISABLE */
+
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s cmd=IOCTL_1588_AUX_TARG_TIME_INTRPT_DISABLE "
+ "invoking pch_aux_target_time_interrupt_disable\n",
+ __func__);
+ if (pch_aux_target_time_interrupt_disable() != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_aux_target_time_interrupt_disable failed\n");
+ ret = -EINVAL;
+ }
+ }
+ return ret;
+}
+
+/**
+ * ioc_handle_port_config() - Handles port config set/get IOCTLs
+ * @cmd: the IOCTL command.
+ * @buf: the port configuration.
+ */
+static s32 ioc_handle_port_config(u32 cmd, s8 *buf, struct pch_dev *pch_pdata)
+{
+ struct pch_portcfg_ioctl *port_cfg_ioctl =
+ (struct pch_portcfg_ioctl *) buf;
+
+ if (cmd == IOCTL_1588_PORT_CONFIG_SET) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s cmd = IOCTL_1588_PORT_CONFIG_SET invoking "
+ "pch_ptp_port_config_set\n", __func__);
+
+ if (pch_ptp_port_config_set(port_cfg_ioctl->ptpport,
+ port_cfg_ioctl->ptpportmode, pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_ptp_port_config_set failed\n");
+ return -EINVAL;
+ }
+ } else { /* IOCTL_1588_PORT_CONFIG_GET */
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s cmd = IOCTL_1588_PORT_CONFIG_GET "
+ "invoking pch_ptp_port_config_get\n", __func__);
+ if (pch_ptp_port_config_get(port_cfg_ioctl->ptpport,
+ &port_cfg_ioctl->ptpportmode, pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_ptp_port_config_get failed\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+/**
+ * ioc_handle_poll() - Handles all poll IOCTLs
+ * @cmd: the IOCTL command.
+ * @buf: the poll configuration.
+ */
+static s32 ioc_handle_poll(u32 cmd, s8 *buf, struct pch_dev *pch_pdata)
+{
+ s32 ret;
+ struct pch_rxtxpoll_ioctl *poll_ioctl =
+ (struct pch_rxtxpoll_ioctl *) buf;
+ struct pch_canpoll_ioctl *can_poll_ioctl =
+ (struct pch_canpoll_ioctl *) buf;
+ struct pch_timepoll_ioctl *time_poll_ioctl =
+ (struct pch_timepoll_ioctl *) buf;
+
+ ret = 0;
+ if (cmd == IOCTL_1588_RX_POLL) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s: cmd = IOCTL_1588_RX_POLL invoking pch_ptp_rx_poll\n",
+ __func__);
+ ret = pch_ptp_rx_poll(poll_ioctl->ptpport,
+ &poll_ioctl->ptpmsgdata, pch_pdata);
+ if ((ret != 0) && (ret != PCH_NOTIMESTAMP)) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_ptp_rx_poll failed\n");
+ ret = -EINVAL;
+ }
+ } else if (cmd == IOCTL_1588_TX_POLL) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s: cmd = IOCTL_1588_TX_POLL invoking pch_ptp_tx_poll\n",
+ __func__);
+ ret = pch_ptp_tx_poll(poll_ioctl->ptpport,
+ &poll_ioctl->ptpmsgdata, pch_pdata);
+ if ((ret != 0) && (ret != PCH_NOTIMESTAMP)) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_ptp_tx_poll failed\n");
+ ret = -EINVAL;
+ }
+ } else if (cmd == IOCTL_1588_CAN_POLL) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s: cmd = IOCTL_1588_CAN_POLL invoking pch_ptp_can_poll\n",
+ __func__);
+ ret = pch_ptp_can_poll(can_poll_ioctl->ptpport,
+ &can_poll_ioctl->ptptimestamp, pch_pdata);
+ if ((ret != 0) && (ret != PCH_NOTIMESTAMP)) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_ptp_can_poll failed\n");
+ ret = -EINVAL;
+ }
+ } else if (cmd == IOCTL_1588_TARG_TIME_POLL) {
+ dev_dbg(&pch_pdata->pdev->dev, "%s: cmd = IOCTL_1588_TARG_TIME_"
+ "POLL invoking pch_target_time_poll\n", __func__);
+ if (pch_target_time_poll(&time_poll_ioctl->poll_flag,
+ &time_poll_ioctl->time_val, pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_target_time_poll failed\n");
+ ret = -EINVAL;
+ }
+ } else if (cmd == IOCTL_1588_AUX_TIME_POLL) {
+ dev_dbg(&pch_pdata->pdev->dev, "%s: cmd = IOCTL_1588_AUX_TIME_P"
+ "OLL invoking pch_aux_time_poll\n", __func__);
+ if (pch_aux_time_poll(time_poll_ioctl->auxmode,
+ &time_poll_ioctl->poll_flag,
+ &time_poll_ioctl->time_val, pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_aux_time_poll failed\n");
+ ret = -EINVAL;
+ }
+ } else { /* IOCTL_1588_AUX_TARG_TIME_POLL */
+
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s: cmd = IOCTL_1588_AUX_TARG_TIME_POLL "
+ "invoking pch_aux_target_time_poll\n", __func__);
+ if (pch_aux_target_time_poll
+ (&time_poll_ioctl->poll_flag,
+ &time_poll_ioctl->time_val) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_aux_target_time_poll failed\n");
+ ret = -EINVAL;
+ }
+ }
+ if ((u32)ret == PCH_NOTIMESTAMP)
+ ret = 0;
+ return ret;
+}
+
+/**
+ * ioc_handle_time_set() - ndles all Time Set IOCTLs
+ * @cmd: the IOCTL command.
+ * @buf: the time value.
+ */
+static s32 ioc_handle_time_set(u32 cmd, s8 *buf, struct pch_dev *pch_pdata)
+{
+ struct pch_tim_val time_value;
+
+ memcpy((void *)&time_value, (const void *)buf,
+ sizeof(struct pch_tim_val));
+
+ if (cmd == IOCTL_1588_SYS_TIME_SET) {
+ dev_dbg(&pch_pdata->pdev->dev, "%s cmd=IOCTL_1588_SYS_TIME_SET "
+ "invoking pch_system_time_set\n", __func__);
+ if (pch_system_time_set(time_value, pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_system_time_set failed\n");
+ return -EINVAL;
+ }
+ } else if (cmd == IOCTL_1588_TARG_TIME_SET) {
+ dev_dbg(&pch_pdata->pdev->dev, "%s cmd=IOCTL_1588_TARG_TIME_SET"
+ " invoking pch_target_time_set\n", __func__);
+ if (pch_target_time_set(time_value, pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_target_time_set failed\n");
+ return -EINVAL;
+ }
+ } else { /* IOCTL_1588_AUX_TARG_TIME_SET */
+
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s cmd=IOCTL_1588_AUX_TARG_TIME_SET "
+ "invoking pch_aux_target_time_set\n", __func__);
+ if (pch_aux_target_time_set(time_value) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_aux_target_time_set failed\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * ioc_handle_time_get() - Handles all Time Get IOCTLs
+ * @cmd: the IOCTL command.
+ * @buf: the time value.
+*/
+static s32 ioc_handle_time_get(u32 cmd, s8 *buf, struct pch_dev *pch_pdata)
+{
+ struct pch_tim_val time_value;
+
+ if (cmd == IOCTL_1588_SYS_TIME_GET) {
+ dev_dbg(&pch_pdata->pdev->dev, "%s cmd=IOCTL_1588_SYS_TIME_GET "
+ "invoking pch_system_time_get\n", __func__);
+ if (pch_system_time_get(&time_value, pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_system_time_get failed\n");
+ return -EINVAL;
+ }
+ } else if (cmd == IOCTL_1588_TARG_TIME_GET) {
+ dev_dbg(&pch_pdata->pdev->dev, "%s cmd=IOCTL_1588_TARG_TIME_GET"
+ " invoking pch_target_time_get\n", __func__);
+ if (pch_target_time_get(&time_value, pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_target_time_get failed\n");
+ return -EINVAL;
+ }
+ } else { /* IOCTL_1588_AUX_TARG_TIME_GET */
+
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s cmd=IOCTL_1588_AUX_TARG_TIME_GET "
+ "invoking pch_aux_target_time_get\n", __func__);
+ if (pch_aux_target_time_get(&time_value)) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_aux_target_time_set failed\n");
+ return -EINVAL;
+ }
+ }
+
+ memcpy((void *)buf, (const void *)&time_value,
+ sizeof(struct pch_tim_val));
+ return 0;
+}
+
+/**
+ * ioc_handle_tick_rate() - Handles tick rate get/set IOCTLs
+ * @cmd: the IOCTL command.
+ * @buf: the tick rate.
+ */
+static s32 ioc_handle_tick_rate(u32 cmd, s8 *buf, struct pch_dev *pch_pdata)
+{
+ u32 val;
+
+ if (cmd == IOCTL_1588_TICK_RATE_GET) {
+ dev_dbg(&pch_pdata->pdev->dev, "%s cmd=IOCTL_1588_TICK_RATE_GET"
+ " invoking pch_tick_rate_get\n", __func__);
+ if (pch_tick_rate_get(&val, pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_tick_rate_get failed\n");
+ return -EINVAL;
+ }
+
+ memcpy((void *)buf, (const void *)&val, sizeof val);
+ } else { /* (cmd == IOCTL_1588_TICK_RATE_SET) */
+
+ dev_dbg(&pch_pdata->pdev->dev, "%s cmd=IOCTL_1588_TICK_RATE_SET"
+ " invoking pch_tick_rate_set\n", __func__);
+ memcpy((void *)&val, (const void *)buf, sizeof val);
+
+ if (pch_tick_rate_set(val, pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_tick_rate_set failed\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+/**
+ * ioc_handle_pps_reqt() - Handles pps time get/set IOCTLs
+ * @cmd: the IOCTL command.
+ * @buf: the pulse per second value.
+ */
+static s32 ioc_handle_pps_reqt(u32 cmd, s8 *buf, struct pch_dev *pch_pdata)
+{
+ u32 val;
+
+ if (cmd == IOCTL_1588_PULSE_PER_SEC_TIME_SET) {
+ dev_dbg(&pch_pdata->pdev->dev, "%s cmd="
+ "IOCTL_1588_PULSE_PER_SEC_TIME_SET "
+ "invoking pch_pulse_per_sec_time_set\n", __func__);
+ memcpy((void *)&val, (const void *)buf, sizeof val);
+ if (pch_pulse_per_sec_time_set(val, pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_pulse_per_sec_time_set failed\n");
+ return -EINVAL;
+ }
+ } else { /* IOCTL_1588_PULSE_PER_SEC_TIME_GET */
+
+ dev_dbg(&pch_pdata->pdev->dev, "%s cmd="
+ "IOCTL_1588_PULSE_PER_SEC_TIME_GET "
+ "invoking pch_pulse_per_sec_time_get\n", __func__);
+ if (pch_pulse_per_sec_time_get(&val, pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_pulse_per_sec_time_get failed\n");
+ return -EINVAL;
+ }
+ memcpy((void *)buf, (const void *)&val, sizeof val);
+ }
+ return 0;
+}
+
+/**
+ * ioc_handle_version_reqt() - Handles ptp version get/set IOCTLs
+ * @cmd: the IOCTL command.
+ * @buf: he ptp version.
+ */
+static s32 ioc_handle_version_reqt(u32 cmd, s8 *buf, struct pch_dev *pch_pdata)
+{
+ struct pch_versionioctl *version_ioctl =
+ (struct pch_versionioctl *) buf;
+
+ if (cmd == IOCTL_1588_PORT_VERSION_SET) {
+ dev_dbg(&pch_pdata->pdev->dev, "%s cmd=IOCTL_1588_PORT_VERSION_"
+ "SET invoking pch_ptp_version_set\n", __func__);
+ if (pch_ptp_version_set
+ (version_ioctl->ptpport,
+ version_ioctl->ptpversion, pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_ptp_version_set failed\n");
+ return -EINVAL;
+ }
+ } else { /* IOCTL_1588_PORT_VERSION_GET */
+
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s cmd=IOCTL_1588_PORT_VERSION_GET "
+ "invoking pch_ptp_version_get\n", __func__);
+ if (pch_ptp_version_get
+ (version_ioctl->ptpport,
+ &version_ioctl->ptpversion, pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_ptp_version_get failed\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+/**
+ * ioc_handle_op_mode_reqt() - Handles ptp operation mode get/set IOCTLs
+ * @cmd: the IOCTL command.
+ * @buf: the ptp operation mode.
+ */
+static s32 ioc_handle_op_mode_reqt(u32 cmd, s8 *buf, struct pch_dev *pch_pdata)
+{
+ struct pch_opemode_ioctl *opmode_ioctl =
+ (struct pch_opemode_ioctl *) buf;
+
+ if (cmd == IOCTL_1588_PORT_OPERATION_MODE_SET) {
+ dev_dbg(&pch_pdata->pdev->dev, "%s cmd="
+ "IOCTL_1588_PORT_OPERATION_MODE_SET "
+ "invoking pch_ptp_operation_mode_set\n", __func__);
+ if (pch_ptp_operation_mode_set
+ (opmode_ioctl->ptpport,
+ opmode_ioctl->ptpopmode, pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_ptp_operation_mode_set failed\n");
+ return -EINVAL;
+ }
+ } else { /* IOCTL_1588_PORT_OPERATION_MODE_GET */
+
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s cmd=IOCTL_1588_PORT_OPERATION_MODE_GET invoking "
+ "pch_ptp_operation_mode_get\n", __func__);
+ if (pch_ptp_operation_mode_get
+ (opmode_ioctl->ptpport, &opmode_ioctl->ptpopmode,
+ pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "pch_ptp_operation_mode_get failed\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static const struct pch_ioc_tbl pch_ioc_tbl_data[] = {
+ {
+ IOCTL_1588_TARG_TIME_NOTIFY, ioc_handle_notify}, {
+ IOCTL_1588_AUX_TIME_NOTIFY, ioc_handle_notify}, {
+ IOCTL_1588_PULSE_PER_SEC_NOTIFY, ioc_handle_notify}, {
+ IOCTL_1588_AUX_TARG_TIME_NOTIFY, ioc_handle_notify}, {
+ IOCTL_1588_TARG_TIME_CLR_NOTIFY, ioc_handle_clr_notify}, {
+ IOCTL_1588_AUX_TIME_CLR_NOTIFY, ioc_handle_clr_notify}, {
+ IOCTL_1588_PULSE_PER_SEC_CLR_NOTIFY, ioc_handle_clr_notify}, {
+ IOCTL_1588_AUX_TARG_TIME_CLR_NOTIFY, ioc_handle_clr_notify}, {
+ IOCTL_1588_RESET, ioc_handle_reset}, {
+ IOCTL_1588_CHNL_RESET, ioc_handle_reset},
+ {
+ IOCTL_1588_SHOW_ALL, ioc_handle_show}, {
+ IOCTL_1588_STATS_GET, ioc_handle_stats}, {
+ IOCTL_1588_STATS_RESET, ioc_handle_stats_reset}, {
+ IOCTL_1588_TARG_TIME_INTRPT_ENABLE, ioc_handle_int_enable}, {
+ IOCTL_1588_AUX_TIME_INTRPT_ENABLE, ioc_handle_int_enable}, {
+ IOCTL_1588_PULSE_PER_SEC_INTRPT_ENABLE, ioc_handle_int_enable}, {
+ IOCTL_1588_AUX_TARG_TIME_INTRPT_ENABLE, ioc_handle_int_enable}, {
+ IOCTL_1588_TARG_TIME_INTRPT_DISABLE, ioc_handle_int_disable}, {
+ IOCTL_1588_AUX_TIME_INTRPT_DISABLE, ioc_handle_int_disable}, {
+ IOCTL_1588_PULSE_PER_SEC_INTRPT_DISABLE, ioc_handle_int_disable}, {
+ IOCTL_1588_AUX_TARG_TIME_INTRPT_DISABLE, ioc_handle_int_disable}, {
+ IOCTL_1588_PORT_CONFIG_SET, ioc_handle_port_config}, {
+ IOCTL_1588_PORT_CONFIG_GET, ioc_handle_port_config}, {
+ IOCTL_1588_RX_POLL, ioc_handle_poll}, {
+ IOCTL_1588_TX_POLL, ioc_handle_poll}, {
+ IOCTL_1588_CAN_POLL, ioc_handle_poll}, {
+ IOCTL_1588_TARG_TIME_POLL, ioc_handle_poll}, {
+ IOCTL_1588_AUX_TIME_POLL, ioc_handle_poll}, {
+ IOCTL_1588_AUX_TARG_TIME_POLL, ioc_handle_poll}, {
+ IOCTL_1588_SYS_TIME_SET, ioc_handle_time_set}, {
+ IOCTL_1588_TARG_TIME_SET, ioc_handle_time_set}, {
+ IOCTL_1588_AUX_TARG_TIME_SET, ioc_handle_time_set}, {
+ IOCTL_1588_SYS_TIME_GET, ioc_handle_time_get}, {
+ IOCTL_1588_TARG_TIME_GET, ioc_handle_time_get}, {
+ IOCTL_1588_AUX_TARG_TIME_GET, ioc_handle_time_get}, {
+ IOCTL_1588_TICK_RATE_GET, ioc_handle_tick_rate}, {
+ IOCTL_1588_TICK_RATE_SET, ioc_handle_tick_rate}, {
+ IOCTL_1588_PULSE_PER_SEC_TIME_SET, ioc_handle_pps_reqt}, {
+ IOCTL_1588_PULSE_PER_SEC_TIME_GET, ioc_handle_pps_reqt}, {
+ IOCTL_1588_PORT_VERSION_SET, ioc_handle_version_reqt}, {
+ IOCTL_1588_PORT_VERSION_GET, ioc_handle_version_reqt}, {
+ IOCTL_1588_PORT_OPERATION_MODE_SET, ioc_handle_op_mode_reqt}, {
+IOCTL_1588_PORT_OPERATION_MODE_GET, ioc_handle_op_mode_reqt},};
+
+
+static long pch_ioctl(struct file *filep, u32 cmd, unsigned long arg)
+{
+ s8 buffer[0x64];
+ u32 argsz;
+ s32 i, ret;
+ struct pch_dev *pch_pdata = (struct pch_dev *)filep->private_data;
+
+ ret = mutex_lock_interruptible(&pch_1588_mutex);
+ if (ret) {
+ ret = -ERESTARTSYS;
+ goto return_nomutex;
+ }
+
+
+ if ((!pch_pdata->initialized) || (pch_pdata->suspend)) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s:device is suspended OR uninitialized\n", __func__);
+ ret = -EBUSY;
+ goto out;
+ }
+ argsz = _IOC_SIZE(cmd);
+
+ if (argsz > sizeof buffer) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s: buffer size too small.\n", __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* if data is being written to the driver */
+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ /* get the data passed in by user */
+ if (copy_from_user(&buffer, (void *)arg, argsz)) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s: could not copy user space data.\n", __func__);
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+
+ for (i = 0; i < PCH_IOC_TBL_ENTRIES; i++) {
+ if (cmd == pch_ioc_tbl_data[i].cmd) {
+ ret = pch_ioc_tbl_data[i].func(cmd, buffer, pch_pdata);
+ break;
+ }
+ }
+ if (i >= PCH_IOC_TBL_ENTRIES) { /* did not find a match */
+ dev_err(&pch_pdata->pdev->dev,
+ "%s: unknown command (0x%x)\n", __func__, cmd);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* if data is being read from the driver */
+ if ((ret == 0) && (_IOC_DIR(cmd) & _IOC_READ)) {
+ if (copy_to_user((void *)arg, buffer, argsz)) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s: could not copy data to user space.\n", __func__);
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+out:
+ mutex_unlock(&pch_1588_mutex);
+return_nomutex:
+ return ret;
+}
+
+
+static const struct file_operations pch_fops = {
+ .owner = THIS_MODULE,
+ .open = pch_open,
+ .release = pch_release,
+ .unlocked_ioctl = pch_ioctl,
+ .llseek = default_llseek
+};
+
+
+static irqreturn_t pch_isr(s32 irq, void *p_data)
+{
+ u32 pending;
+ struct pch_dev *pch_pdata = (struct pch_dev *)p_data;
+
+
+ pending = pch_interrupt_pending(pch_pdata);
+ if (!pending) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s: no pending interrupt\n", __func__);
+ return IRQ_NONE;
+ }
+
+ if (pch_handler(pch_pdata) != 0) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s: pch_handler failed\n", __func__);
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static const struct pci_device_id pch_pcidev_id[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH_1588)},
+ {0},
+};
+
+
+static s32 __devinit
+pch_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ s32 ret;
+ dev_t devno;
+ s32 i;
+
+ struct pch_dev *chip;
+
+ chip = kzalloc(sizeof(struct pch_dev), GFP_KERNEL);
+ if (chip == NULL)
+ return -ENOMEM;
+
+ UNUSED_ARG(id);
+
+ /* enable the 1588 pci device */
+ ret = pci_enable_device(pdev);
+ if (ret != 0) {
+ dev_err(&pdev->dev,
+ "%s:could not enable the pci device\n", __func__);
+ goto err_pci_en;
+ }
+ dev_dbg(&pdev->dev, "%s:pci_enable_device success\n", __func__);
+
+ chip->mem_base = pci_resource_start(pdev, IO_MEM_BAR);
+
+ if (!chip->mem_base) {
+ dev_err(&pdev->dev,
+ "%s: could not locate IO memory address\n", __func__);
+ ret = -ENODEV;
+ goto err_pci_start;
+ }
+ dev_dbg(&pdev->dev, "%s:allocated IO memory address\n", __func__);
+
+ /* retreive the available length of the IO memory space */
+ chip->mem_size = pci_resource_len(pdev, IO_MEM_BAR);
+
+ /* allocate the memory for the device registers */
+ if (!request_mem_region
+ (chip->mem_base, chip->mem_size, "1588_regs")) {
+ dev_err(&pdev->dev,
+ "%s: could not allocate register memory space\n", __func__);
+ ret = -EBUSY;
+ goto err_req_mem_region;
+ }
+ dev_dbg(&pdev->dev, "%s:allocated register memory space\n", __func__);
+
+ /* get the virtual address to the 1588 registers */
+ chip->mem_virt = ioremap(chip->mem_base, chip->mem_size);
+
+ if (!chip->mem_virt) {
+ dev_err(&pdev->dev,
+ "%s: Could not get virtual address\n", __func__);
+ ret = -ENOMEM;
+ goto err_ioremap;
+ }
+ dev_dbg(&pdev->dev, "%s:obtained virtual address=%p\n", __func__,
+ chip->mem_virt);
+
+ for (i = 0; i < NUM_EVENTS; i++) {
+ init_waitqueue_head(&chip->notify_evt[i]);
+ chip->event_flags[i] = 0;
+ }
+ dev_dbg(&pdev->dev, "%s:initialized wait queue heads\n", __func__);
+
+ pch_blpl_base_address_set(chip);
+
+ spin_lock_init(&chip->lock);
+
+ ret = request_irq(pdev->irq, &pch_isr, IRQF_SHARED, MODULE_NAME,
+ chip);
+ if (ret != 0) {
+ dev_err(&pdev->dev,
+ "%s: failed to get irq %d\n", __func__, pdev->irq);
+ goto err_req_irq;
+ }
+ dev_dbg(&pdev->dev,
+ "%s:registered IRQ handler successfully\n", __func__);
+
+ /* register the module */
+ if (pch_param.major != 0) { /* user specified a major
+ number, use it */
+ dev_dbg(&pdev->dev,
+ "%s:using user specified major number\n", __func__);
+ devno = MKDEV(pch_param.major, 0);
+ ret = register_chrdev_region(devno, 1, MODULE_NAME);
+ chip->devno = devno; /* store it */
+ } else { /* request and reserve a device number */
+
+ dev_dbg(&pdev->dev,
+ "%s:dynamically allocating major number\n", __func__);
+ ret = alloc_chrdev_region(&chip->devno, 0, 1, MODULE_NAME);
+ devno = MKDEV(MAJOR(chip->devno), 0);
+ }
+ if (ret < 0) {
+ dev_err(&pdev->dev, "%s: Couldn't register module (major %d)\n",
+ __func__, pch_param.major);
+ goto err_alloc_chardev;
+ }
+ dev_dbg(&pdev->dev, "%s:registered the module(major %d)\n",
+ __func__, pch_param.major);
+
+ /* init cdev struct for adding device to kernel */
+ cdev_init(&chip->cdev, &pch_fops);
+ chip->cdev.owner = THIS_MODULE;
+ chip->cdev.ops = &pch_fops;
+
+ ret = cdev_add(&chip->cdev, devno, 1);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "%s: cdev_add failed\n", __func__);
+ goto err_cdev_add;
+ }
+ dev_dbg(&pdev->dev, "%s: cdev_add successful\n", __func__);
+
+ chip->initialized = 1;
+ /* indicate success */
+ chip->irq = pdev->irq;
+
+ chip->pdev = pdev;
+
+ pci_set_drvdata(pdev, chip);
+
+ /* reset the ieee1588 h/w */
+ pch_reset(chip);
+
+ if (pch_param.eth_enable != 0) { /* Enable by default */
+ dev_dbg(&pdev->dev,
+ "%s: invoking pch_eth_enable to enable ethernet\n", __func__);
+ pch_eth_enable(chip);
+ } else {
+ dev_dbg(&pdev->dev,
+ "%s: invoking pch_eth_disable to disable ethernet\n",
+ __func__);
+ pch_eth_disable(chip);
+ }
+ if (pch_param.can_enable == 1) { /* Enable if requested */
+ dev_dbg(&pdev->dev,
+ "%s: invoking pch_can_enable to enable CAN\n", __func__);
+ pch_can_enable(chip);
+ } else {
+ dev_dbg(&pdev->dev,
+ "%s: invoking pch_can_disable to disable CAN\n", __func__);
+ pch_can_disable(chip);
+ }
+ if (strcmp(pch_param.station, "00:00:00:00:00:00") != 0) {
+ if (pch_set_station_address(pch_param.station, pdev) != 0) {
+ dev_err(&pdev->dev,
+ "%s: Invalid station address parameter\n"
+ "Module loaded; But, station address not set "
+ "correctly\n", __func__);
+ }
+ }
+ dev_dbg(&pdev->dev, "%s: probe succeeded\n", __func__);
+
+ return 0;
+
+err_cdev_add:
+ unregister_chrdev_region(chip->devno, 1);
+
+err_alloc_chardev:
+ free_irq(pdev->irq, chip);
+
+err_req_irq:
+ iounmap(chip->mem_virt);
+ chip->mem_virt = 0;
+
+err_ioremap:
+ release_mem_region(chip->mem_base, chip->mem_size);
+
+err_req_mem_region:
+ chip->mem_base = 0;
+
+err_pci_start:
+ pci_disable_device(pdev);
+
+err_pci_en:
+ kfree(chip);
+ dev_err(&pdev->dev, "%s: probe failed(ret=0x%x)\n", __func__, ret);
+
+ return ret;
+}
+
+static void __devexit pch_remove(struct pci_dev *pdev)
+{
+ struct pch_dev *chip = pci_get_drvdata(pdev);
+ unregister_chrdev_region(chip->devno, 1);
+ dev_dbg(&pdev->dev, "%s:unregisterd the module\n", __func__);
+
+ /* free the interrupt */
+ if (pdev->irq != 0) {
+ free_irq(pdev->irq, chip);
+ dev_dbg(&pdev->dev, "%s: unregistered IRQ handler\n", __func__);
+ }
+
+ /* unmap the virtual IO memory space */
+ if (chip->mem_virt != 0) {
+ iounmap(chip->mem_virt);
+ chip->mem_virt = 0;
+ dev_dbg(&pdev->dev,
+ "%s: unmaped the virtual IO memory space\n", __func__);
+ }
+
+ /* release the reserved IO memory space */
+ if (chip->mem_base != 0) {
+ release_mem_region(chip->mem_base, chip->mem_size);
+ chip->mem_base = 0;
+ dev_dbg(&pdev->dev,
+ "%s: released the reserved IO memory space\n", __func__);
+ }
+
+ pci_disable_device(pdev);
+
+ kfree(chip);
+
+ dev_dbg(&pdev->dev, "%s:disabled the device\n", __func__);
+
+ dev_info(&pdev->dev, "%s: complete\n", __func__);
+}
+
+#ifdef CONFIG_PM
+static s32 pch_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct pch_dev *chip = pci_get_drvdata(pdev);
+ dev_dbg(&pdev->dev,
+ "%s: disabling interrupts by invoking pch_disable_interrupts\n",
+ __func__);
+ pch_disable_interrupts(chip);
+
+ chip->suspend = 1;
+
+ dev_dbg(&pdev->dev,
+ "%s: saving register values by invoking pch_save_state\n",
+ __func__);
+ pch_save_state(pdev);
+
+ pci_disable_device(pdev);
+ dev_dbg(&pdev->dev, "%s: disabled the device\n", __func__);
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ dev_dbg(&pdev->dev, "%s: disabled PM notifications\n", __func__);
+
+ if (pci_save_state(pdev) != 0) {
+ dev_err(&pdev->dev,
+ "%s: could not save PCI config state\n", __func__);
+ return -ENOMEM;
+ }
+ dev_dbg(&pdev->dev, "%s: saved state\n", __func__);
+
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ dev_dbg(&pdev->dev, "%s: returning success\n", __func__);
+ return 0;
+}
+
+static s32 pch_resume(struct pci_dev *pdev)
+{
+ s32 ret;
+ struct pch_dev *chip = pci_get_drvdata(pdev);
+
+ pci_set_power_state(pdev, PCI_D0);
+
+ ret = pci_restore_state(pdev);
+
+ if (ret != 0) {
+ dev_err(&pdev->dev, "%s: pci_restore_state failed\n", __func__);
+ return ret;
+ }
+ dev_dbg(&pdev->dev, "%s: restored state\n", __func__);
+
+ ret = pci_enable_device(pdev);
+
+ if (ret) {
+ dev_err(&pdev->dev, "%s: pci_enable_device failed\n", __func__);
+ return ret;
+ }
+
+ dev_dbg(&pdev->dev, "%s: enabled device\n", __func__);
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ dev_dbg(&pdev->dev, "%s: disabled PM notifications\n", __func__);
+
+ pch_restore_state(pdev);
+
+ chip->suspend = 0;
+
+ dev_dbg(&pdev->dev, "%s: returning success\n", __func__);
+ return 0;
+}
+#else
+#define pch_suspend NULL
+#define pch_resume NULL
+#endif
+
+static struct pci_driver pch_pcidev = {
+ .name = MODULE_NAME,
+ .id_table = pch_pcidev_id,
+ .probe = pch_probe,
+ .remove = pch_remove,
+ .suspend = pch_suspend,
+ .resume = pch_resume,
+};
+
+static void __exit pch_exit(void)
+{
+ pci_unregister_driver(&pch_pcidev);
+}
+
+static s32 __init pch_init(void)
+{
+ s32 ret;
+
+ /* register the driver with the pci core */
+ ret = pci_register_driver(&pch_pcidev);
+
+ return ret;
+}
+
+module_param_named(eth_enable, pch_param.eth_enable, bool, 0444);
+MODULE_PARM_DESC(eth_enable,
+ "IEEE 1588 on ethernet interface 0=Disabled 1=Enabled (default 1)");
+
+module_param_named(can_enable, pch_param.can_enable, bool, 0444);
+MODULE_PARM_DESC(can_enable,
+ "IEEE 1588 on CAN interface 0=Disabled 1=Enabled (default 0)");
+
+module_param_named(major, pch_param.major, int, 0444);
+MODULE_PARM_DESC(major,
+ "IEEE 1588 device major number to use (default system assigned)");
+
+module_param_string(station, pch_param.station,
+ sizeof pch_param.station, 0444);
+MODULE_PARM_DESC(station,
+ "IEEE 1588 station address to use - column separated hex values");
+
+module_init(pch_init);
+module_exit(pch_exit);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pch_pcidev_id);
diff --git a/drivers/char/pch_ieee1588/pch_ieee1588.h b/drivers/char/pch_ieee1588/pch_ieee1588.h
new file mode 100644
index 0000000..3571935
--- /dev/null
+++ b/drivers/char/pch_ieee1588/pch_ieee1588.h
@@ -0,0 +1,528 @@
+/*
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef PCH_MAIN_H
+#define PCH_MAIN_H
+
+#ifdef __GNUC__
+#define UNUSED __attribute__ ((unused))
+#define UNUSED_ARG(x)
+#else
+#define UNUSED
+#define UNUSED_ARG(x) (void) x
+#endif
+
+
+#define TRUE 1
+#define FALSE 0
+
+
+
+#define IOC_1588_BASE 0xf8
+
+#define IOCTL_1588_PORT_CONFIG_SET \
+ _IOW(IOC_1588_BASE, 0, struct pch_portcfg_ioctl)
+
+#define IOCTL_1588_PORT_CONFIG_GET \
+ _IOWR(IOC_1588_BASE, 1, struct pch_portcfg_ioctl)
+
+#define IOCTL_1588_RX_POLL _IOWR(IOC_1588_BASE, 2, struct pch_rxtxpoll_ioctl)
+
+#define IOCTL_1588_TX_POLL _IOWR(IOC_1588_BASE, 3, struct pch_rxtxpoll_ioctl)
+
+#define IOCTL_1588_CAN_POLL _IOWR(IOC_1588_BASE, 4, struct pch_canpoll_ioctl)
+
+#define IOCTL_1588_SYS_TIME_GET _IOR(IOC_1588_BASE, 5, struct pch_tim_val)
+
+#define IOCTL_1588_SYS_TIME_SET _IOW(IOC_1588_BASE, 6, struct pch_tim_val)
+
+#define IOCTL_1588_TICK_RATE_SET _IOW(IOC_1588_BASE, 7, __u32)
+
+#define IOCTL_1588_TICK_RATE_GET _IOR(IOC_1588_BASE, 8, __u32)
+
+#define IOCTL_1588_TARG_TIME_INTRPT_ENABLE _IO(IOC_1588_BASE, 9)
+
+#define IOCTL_1588_TARG_TIME_INTRPT_DISABLE _IO(IOC_1588_BASE, 10)
+
+#define IOCTL_1588_TARG_TIME_POLL \
+ _IOR(IOC_1588_BASE, 11, struct pch_timepoll_ioctl)
+
+#define IOCTL_1588_TARG_TIME_SET \
+ _IOW(IOC_1588_BASE, 12, struct pch_tim_val)
+
+#define IOCTL_1588_TARG_TIME_GET \
+ _IOR(IOC_1588_BASE, 13, struct pch_tim_val)
+
+#define IOCTL_1588_AUX_TIME_INTRPT_ENABLE _IOW(IOC_1588_BASE, 14,\
+ enum pch_auxmode)
+
+#define IOCTL_1588_AUX_TIME_INTRPT_DISABLE _IOW(IOC_1588_BASE, 15,\
+ enum pch_auxmode)
+
+#define IOCTL_1588_AUX_TIME_POLL \
+ _IOWR(IOC_1588_BASE, 16, struct pch_timepoll_ioctl)
+
+#define IOCTL_1588_RESET _IO(IOC_1588_BASE, 17)
+
+#define IOCTL_1588_CHNL_RESET _IOW(IOC_1588_BASE, 18, enum pch_ptpport)
+
+#define IOCTL_1588_STATS_GET _IOR(IOC_1588_BASE, 19, struct pch_stats)
+
+#define IOCTL_1588_STATS_RESET _IO(IOC_1588_BASE, 20)
+
+#define IOCTL_1588_SHOW_ALL _IO(IOC_1588_BASE, 21)
+
+#define IOCTL_1588_AUX_TARG_TIME_INTRPT_ENABLE _IO(IOC_1588_BASE, 22)
+
+#define IOCTL_1588_AUX_TARG_TIME_INTRPT_DISABLE _IO(IOC_1588_BASE, 23)
+
+#define IOCTL_1588_AUX_TARG_TIME_POLL \
+ _IOR(IOC_1588_BASE, 24, struct pch_timepoll_ioctl)
+
+#define IOCTL_1588_AUX_TARG_TIME_SET \
+ _IOW(IOC_1588_BASE, 25, struct pch_tim_val)
+
+#define IOCTL_1588_AUX_TARG_TIME_GET \
+ _IOR(IOC_1588_BASE, 26, struct pch_tim_val)
+
+#define IOCTL_1588_PULSE_PER_SEC_INTRPT_ENABLE _IO(IOC_1588_BASE, 27)
+
+#define IOCTL_1588_PULSE_PER_SEC_INTRPT_DISABLE _IO(IOC_1588_BASE, 28)
+
+#define IOCTL_1588_TARG_TIME_NOTIFY \
+ _IOR(IOC_1588_BASE, 29, struct pch_tim_val)
+
+#define IOCTL_1588_AUX_TIME_NOTIFY \
+ _IOR(IOC_1588_BASE, 30, struct pch_auxtimeioctl)
+
+#define IOCTL_1588_AUX_TARG_TIME_NOTIFY \
+ _IOR(IOC_1588_BASE, 31, struct pch_tim_val)
+
+#define IOCTL_1588_PULSE_PER_SEC_NOTIFY _IOR(IOC_1588_BASE, 32, __u32)
+
+#define IOCTL_1588_TARG_TIME_CLR_NOTIFY _IO(IOC_1588_BASE, 33)
+
+#define IOCTL_1588_AUX_TIME_CLR_NOTIFY _IO(IOC_1588_BASE, 34)
+
+#define IOCTL_1588_AUX_TARG_TIME_CLR_NOTIFY _IO(IOC_1588_BASE, 35)
+
+#define IOCTL_1588_PULSE_PER_SEC_CLR_NOTIFY _IO(IOC_1588_BASE, 36)
+
+#define IOCTL_1588_PULSE_PER_SEC_TIME_GET _IOR(IOC_1588_BASE, 37, __u32)
+
+#define IOCTL_1588_PULSE_PER_SEC_TIME_SET _IOW(IOC_1588_BASE, 38, __u32)
+
+#define IOCTL_1588_PORT_VERSION_SET \
+ _IOW(IOC_1588_BASE, 39, struct pch_versionioctl)
+
+#define IOCTL_1588_PORT_VERSION_GET \
+ _IOWR(IOC_1588_BASE, 40, struct pch_versionioctl)
+
+#define IOCTL_1588_PORT_OPERATION_MODE_SET \
+ _IOW(IOC_1588_BASE, 41, struct pch_opemode_ioctl)
+
+#define IOCTL_1588_PORT_OPERATION_MODE_GET \
+ _IOWR(IOC_1588_BASE, 42, struct pch_opemode_ioctl)
+
+
+#define PCH_TSC_OFFSET 0x00 /* TS_Control */
+#define PCH_TSE_OFFSET 0x04 /* TS_Event */
+#define PCH_ADD_OFFSET 0x08 /* TS_Addend */
+#define PCH_ACC_OFFSET 0x0C /* TS_Accum */
+#define PCH_TST_OFFSET 0x10 /* TS_Test */
+#define PCH_PPS_OFFSET 0x14 /* TS_PPS_Compare */
+#define PCH_STL_OFFSET 0x20 /* TS_SysTimeLo */
+#define PCH_STH_OFFSET 0x24 /* TS_SysTimeHi */
+#define PCH_TTL_OFFSET 0x28 /* TS_TrgtLo */
+#define PCH_TTH_OFFSET 0x2c /* TS_TrgtHi */
+#define PCH_ASSL_OFFSET 0x30 /* TS_ASMSLo */
+#define PCH_ASSH_OFFSET 0x34 /* TS_ASMSHi */
+#define PCH_AMSL_OFFSET 0x38 /* TS_AMMSLo */
+#define PCH_AMSH_OFFSET 0x3C /* TS_AMMSHi */
+#define PCH_CC_OFFSET 0x40 /* TS_Ch_Contr */
+#define PCH_CE_OFFSET 0x44 /* TS_Ch_Event */
+#define PCH_XSL_OFFSET 0x48 /* TS_TxSnapLo */
+#define PCH_XSH_OFFSET 0x4C /* TS_TxSnapHi */
+#define PCH_RSL_OFFSET 0x50 /* TS_RxSnapLo */
+#define PCH_RSH_OFFSET 0x54 /* TS_RxSnapHi */
+#define PCH_UID_OFFSET 0x58 /* TS_SrcUUID */
+#define PCH_SID_OFFSET 0x5C /* TS_SrcUUID */
+#define PCH_CCE_OFFSET 0x60 /* TS_CAN_Stat */
+#define PCH_CXSL_OFFSET 0x64 /* TS_CAN_Snap */
+#define PCH_CXSH_OFFSET 0x68 /* TS_CAN_Snap */
+#define PCH_ECS_OFFSET 0x6c /* TS_SEL */
+#define PCH_STA_OFFSET 0x70 /* TS_ST1 */
+
+#define PCH_TSC_RESET_SHIFT 0
+
+#define PCH_TSC_RESET (1 << PCH_TSC_RESET_SHIFT)
+
+#define PCH_TSC_TTM_SHIFT 1
+#define PCH_TSC_TTM_MASK (1 << PCH_TSC_TTM_SHIFT)
+#define PCH_TSC_ASMS_SHIFT 2
+#define PCH_TSC_ASMS_MASK (1 << PCH_TSC_ASMS_SHIFT)
+#define PCH_TSC_AMMS_SHIFT 3
+#define PCH_TSC_AMMS_MASK (1 << PCH_TSC_AMMS_SHIFT)
+#define PCH_TSC_PPSM_SHIFT 4
+#define PCH_TSC_PPSM_MASK (1 << PCH_TSC_PPSM_SHIFT)
+#define PCH_TSE_TTIPEND_SHIFT 1
+#define PCH_TSE_TTIPEND (1 << PCH_TSE_TTIPEND_SHIFT)
+#define PCH_TSE_SNS_SHIFT 2
+#define PCH_TSE_SNS (1 << PCH_TSE_SNS_SHIFT)
+#define PCH_TSE_SNM_SHIFT 3
+#define PCH_TSE_SNM (1 << PCH_TSE_SNM_SHIFT)
+#define PCH_TSE_PPS_SHIFT 4
+#define PCH_TSE_PPS (1 << PCH_TSE_PPS_SHIFT)
+#define PCH_CC_MM_SHIFT 0
+#define PCH_CC_MM (1 << PCH_CC_MM_SHIFT)
+#define PCH_CC_TA_SHIFT 1
+
+#define PCH_CC_TA (1 << PCH_CC_TA_SHIFT)
+#define PCH_CC_MODE_SHIFT 16
+#define PCH_CC_MODE_MASK 0x001F0000
+#define PCH_CC_VERSION_SHIFT 31
+#define PCH_CC_VERSION (1 << PCH_CC_VERSION_SHIFT)
+#define PCH_CE_TXS (1 << 0)
+#define PCH_CE_RXS (1 << 1)
+#define PCH_CE_OVR (1 << 0)
+#define PCH_CE_VAL (1 << 1)
+#define PCH_ECS_ETH_SHIFT 0
+#define PCH_ECS_ETH (1 << PCH_ECS_ETH_SHIFT)
+
+#define PCH_ECS_CAN_SHIFT 1
+#define PCH_ECS_CAN (1 << PCH_ECS_CAN_SHIFT)
+#define PCH_STATION_BYTES 6
+#define MODULE_NAME "pch_ieee1588"
+
+#define PCH_IEEE1588_ETH (1 << 0)
+#define PCH_IEEE1588_CAN (1 << 1)
+
+#define STATION_ADDR_LEN 20
+#define PCI_DEVICE_ID_PCH_1588 0x8819
+#define IO_MEM_BAR 1
+
+/* Register read/write macros */
+#define PCH_REG_32_READ(regAddr, varRef) (*(varRef) = ioread32(regAddr))
+#define PCH_REG_32_WRITE(regAddr, varValue) iowrite32(varValue, regAddr)
+#define PCH_BIT_SET_CHECK(regAddr, bitMask) \
+ ((ioread32(regAddr) & (bitMask)) == (bitMask))
+
+#define PCH_SET_ADDR_BIT(addr, bitmask) iowrite32((ioread32(addr) |\
+ (bitmask)), (addr))
+#define PCH_CLR_ADDR_BIT(addr, bitmask) iowrite32((ioread32(addr) &\
+ ~(bitmask)), (addr))
+
+/* Masks to extract High and Low SHORTs from u32 values */
+#define PCH_MSB_SHORT_MASK 0xFFFF0000
+#define PCH_LSB_SHORT_MASK 0x0000FFFF
+
+/* Location of SeqID in the register */
+#define PCH_SID_LOC 16
+
+
+enum pch_ptpport {
+ PCH_GBE_0_1588PTP_PORT,
+ PCH_CAN_0_1588PTP_PORT,
+ PCH_PORT_INVALID
+};
+
+
+enum pch_ptpportmode {
+ PCH_1588PTP_PORT_MASTER,
+ PCH_1588PTP_PORT_SLAVE,
+ PCH_1588PTP_PORT_ANYMODE,
+ PCH_1588PTP_PORT_MODE_INVALID
+};
+
+enum pch_ptpmsgtype {
+ PCH_1588PTP_MSGTYPE_SYNC,
+ PCH_1588PTP_MSGTYPE_DELAYREQ,
+ PCH_1588PTP_MSGTYPE_UNKNOWN
+};
+
+enum pch_auxmode{
+ PCH_AUXMODE_MASTER,
+ PCH_AUXMODE_SLAVE,
+ PCH_AUXMODE_INVALID
+};
+
+enum pch_ptpversion {
+ PCH_1588PTP_VERSION_0,
+ PCH_1588PTP_VERSION_1,
+ PCH_1588PTP_VERSION_INVALID
+};
+
+enum pch_ptpope_mode {
+ PCH_1588PTP_OP_MODE_SYNC_DELAYREQ_MSGS,
+ PCH_1588PTP_OP_MODE_V1_ALL_MSGS,
+ PCH_1588PTP_OP_MODE_V1_V2_EVENT_MSGS,
+ PCH_1588PTP_OP_MODE_V1_V2_ALL_MSGS,
+ PCH_1588PTP_OP_MODE_INVALID
+};
+
+enum pch_status {
+ PCH_SUCCESS,
+ PCH_INVALIDPARAM,
+ PCH_NOTIMESTAMP,
+ PCH_INTERRUPTMODEINUSE,
+ PCH_FAILED,
+ PCH_UNSUPPORTED,
+};
+
+enum _notify_event {
+ TARG_TIME_EVENT_NUM,
+ AUX_TIME_EVENT_NUM,
+ PPS_EVENT_NUM,
+ NUM_EVENTS
+};
+
+/**
+ * struct pch_portcfg_ioctl - Struct to pass port config data for ioctl call
+ * @ptpport: IEEE 1588 PTP Communication Port
+ * @ptpportmode: Master, Slave,or Any mode
+ */
+struct pch_portcfg_ioctl {
+ enum pch_ptpport ptpport;
+ enum pch_ptpportmode ptpportmode;
+};
+
+/**
+ * struct pch_tim_val - Struct to hold 64 bit SystemTime and TimeStamp
+ * values
+ * @tim_val_low_word: Lower 32 bits of time value
+ * @tim_val_high_word: Upper 32 bits of time value
+ */
+struct pch_tim_val {
+ __u32 tim_val_low_word;
+ __u32 tim_val_high_word;
+};
+
+/**
+ * struct pch_uuid - Struct to hold 48 bit UUID values captured in Sync or
+ * Delay_Req messages
+ * @uuid_val_low_word: The lower 32 bits of UUID
+ * @uuid_val_high_half_word: The upper 16 bits of UUID.
+ */
+struct pch_uuid{
+ __u32 uuid_val_low_word;
+ __u32 uuid_val_high_half_word;
+};
+
+/**
+ * struct pch_ptpmsgdata - Struct for data from the PTP message returned when
+ * TimeStamp available
+ * @pch_ptpmsgtype ptpmsgtype: PTP Messages type
+ * @ptptimestamp: 64 bit TimeStamp value from PTP Message
+ * @ptpuuid: 48 bit UUID value from the PTP Message
+ * @ptpsequencenumber: 16 bit Sequence Number from PTP Message
+ */
+struct pch_ptpmsgdata{
+ enum pch_ptpmsgtype ptpmsgtype;
+ struct pch_tim_val ptptimestamp;
+ struct pch_uuid ptpuuid;
+ u32 ptpsequencenumber;
+};
+
+/**
+ * struct pch_rxtxpoll_ioctl - Struct to pass PTP message data for ioctl call
+ * @ptpport: IEEE 1588 PTP Communication Port
+ * @ptpmsgdata: PTP message data
+ */
+struct pch_rxtxpoll_ioctl{
+ enum pch_ptpport ptpport;
+ struct pch_ptpmsgdata ptpmsgdata;
+};
+
+/**
+ * struct pch_canpoll_ioctl - Struct to pass CAN timestamp data for ioctl call
+ * @ptpport: IEEE 1588 PTP Communication Port
+ * @ptptimestamp: CAN PTP timestamp
+ */
+struct pch_canpoll_ioctl{
+ enum pch_ptpport ptpport;
+ struct pch_tim_val ptptimestamp;
+};
+
+/**
+ * struct pch_timepoll_ioctl - Struct to pass timestamp data for ioctl call
+ * @poll_flag: time event
+ * @time_val: timestamp value
+ * @auxmode: Master or Slave mode
+ */
+struct pch_timepoll_ioctl {
+ __u32 poll_flag;
+ struct pch_tim_val time_val;
+ enum pch_auxmode auxmode;
+};
+
+/**
+ * struct pch_stats - Provides the number of times timestamps are locked for
+ * rx and tx PTP
+ * @rxmsgs: Count of timestamps for received PTP Msgs
+ * @txmsgs: Count of timestamps for transmitted PTP Msgs
+ */
+struct pch_stats {
+ __u32 rxmsgs;
+ __u32 txmsgs;
+};
+
+/**
+ * struct pch_auxtimeioctl - Struct to pass aux time data for ioctl call
+ * @auxmode: aux mode: master or slave
+ * @auxtime: aux time snapshot
+ */
+struct pch_auxtimeioctl {
+ enum pch_auxmode auxmode;
+ struct pch_tim_val auxtime;
+};
+
+/**
+ * struct pch_versionioctl - Struct to pass timestamp data for ioctl call
+ * @ptpport: IEEE 1588 PTP Communication Port
+ * @ptpversion: version value
+ */
+struct pch_versionioctl {
+ enum pch_ptpport ptpport;
+ enum pch_ptpversion ptpversion;
+};
+
+/**
+ * struct pch_opemode_ioctl - Struct to pass timestamp data for ioctl
+ * call
+ * @ptpport: IEEE 1588 PTP Communication Port
+ * @ptpopmode: IEEE 1588 operation mode
+ */
+struct pch_opemode_ioctl {
+ enum pch_ptpport ptpport;
+ enum pch_ptpope_mode ptpopmode;
+};
+
+/**
+ * struct pch_regs_set - IEEE 1588 registers to save and restore on
+ * suspend/resume
+ * @ts_control: Time stamp control register
+ * @ts_event: Time stamp event register
+ * @ts_addend: Addend register
+ * @ts_accum: unused
+ * @ts_test: unused
+ * @ts_compare: PPS comapre register
+ * @ts_syslo: System time Low registers
+ * @ts_syshi: System time Hi registers
+ * @ts_tgtlo: Target time Low registers
+ * @ts_tgthi: Target time Hi registers
+ * @ts_asmslo: unused
+ * @ts_asmshi: unused
+ * @ts_ammslo: unused
+ * @ts_ammshi: unused
+ * @ts_cc: CAN Channel event register
+ * @ts_ce: Channel event register
+ * @ts_xslo: unused
+ * @ts_xshi: unused
+ * @ts_rslo: unused
+ * @ts_rshi: unused
+ * @ts_uuidlo: unused
+ * @ts_uuidhi: unused
+ * @ts_cce: unused
+ * @ts_cxslo: unused
+ * @ts_cxshi: unused
+ * @ts_sel: Selector
+ * @ts_sti: station addresses
+ */
+struct pch_regs_set {
+ u32 ts_control;
+ u32 ts_event;
+ u32 ts_addend;
+ u32 ts_accum;
+ u32 ts_test;
+ u32 ts_compare;
+ u32 ts_syslo;
+ u32 ts_syshi;
+ u32 ts_tgtlo;
+ u32 ts_tgthi;
+ u32 ts_asmslo;
+ u32 ts_asmshi;
+ u32 ts_ammslo;
+ u32 ts_ammshi;
+
+ /* Ethernet */
+ u32 ts_cc;
+ u32 ts_ce;
+ u32 ts_xslo;
+ u32 ts_xshi;
+ u32 ts_rslo;
+ u32 ts_rshi;
+ u32 ts_uuidlo;
+ u32 ts_uuidhi;
+
+ /* CAN */
+ u32 ts_cce;
+ u32 ts_cxslo;
+ u32 ts_cxshi;
+
+ u32 ts_sel;
+ u8 ts_sti[6];
+};
+
+/**
+ * struct pch_dev - Driver private data
+ * @devno: The device (major) number
+ * @cdev: The cdev structure instance
+ * @mem_virt: The virtual memory base address
+ * @mem_base: The physical memory base address
+ * @mem_size: The memory size
+ * @irq: The IRQ line of the device
+ * @suspend: The suspend flag
+ * @initialized:The initialized flag
+ * @event_flags:The event variables
+ * @notify_evt: The notify event variable
+ */
+struct pch_dev {
+ dev_t devno;
+ struct cdev cdev;
+ void __iomem *mem_virt;
+ u32 mem_base;
+ u32 mem_size;
+ u32 irq;
+ u32 suspend:1;
+ u32 initialized:1;
+ u32 event_flags[NUM_EVENTS];
+ wait_queue_head_t notify_evt[NUM_EVENTS];
+ struct pci_dev *pdev;
+ spinlock_t lock;
+};
+
+/* Structure to map the ioctl command to the associated function */
+struct pch_ioc_tbl {
+ u32 cmd;
+ s32 (*func) (u32, s8 *, struct pch_dev *);
+};
+
+/**
+ * struct ch_1588_params_ - 1588 module paramter
+ * @eth_enable: IEEE 1588 on ethernet interface
+ * @can_enable: IEEE 1588 on CAN interface
+ * @major: IEEE 1588 device major number to use (default system assigned)
+ * @station: IEEE 1588 station address to use - column separated hex values
+ */
+struct pch_params_ {
+ s32 eth_enable;
+ s32 can_enable;
+ s32 major;
+ u8 station[STATION_ADDR_LEN];
+};
+
+#endif /* PCH_H */
--
1.6.0.6



\
 
 \ /
  Last update: 2010-08-10 12:35    [W:0.231 / U:1.780 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site