/*
* Driver for the National Semiconductor DP83640 PHYTER
*
* Copyright (C) 2010 OMICRON electronics GmbH
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/ethtool.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/mii.h>
#include <linux/module.h>
#include <linux/net_tstamp.h>
#include <linux/netdevice.h>
#include <linux/phy.h>
#include <linux/ptp_classify.h>
#include <linux/ptp_clock_kernel.h>
#include "dp83640_reg.h"
#define DP83640_PHY_ID 0x20005ce1
#define PAGESEL 0x13
#define LAYER4 0x02
#define LAYER2 0x01
#define MAX_RXTS 64
#define N_EXT_TS 6
#define PSF_PTPVER 2
#define PSF_EVNT 0x4000
#define PSF_RX 0x2000
#define PSF_TX 0x1000
#define EXT_EVENT 1
#define CAL_EVENT 7
#define CAL_TRIGGER 7
#define PER_TRIGGER 6
#define MII_DP83640_MICR 0x11
#define MII_DP83640_MISR 0x12
#define MII_DP83640_MICR_OE 0x1
#define MII_DP83640_MICR_IE 0x2
#define MII_DP83640_MISR_RHF_INT_EN 0x01
#define MII_DP83640_MISR_FHF_INT_EN 0x02
#define MII_DP83640_MISR_ANC_INT_EN 0x04
#define MII_DP83640_MISR_DUP_INT_EN 0x08
#define MII_DP83640_MISR_SPD_INT_EN 0x10
#define MII_DP83640_MISR_LINK_INT_EN 0x20
#define MII_DP83640_MISR_ED_INT_EN 0x40
#define MII_DP83640_MISR_LQ_INT_EN 0x80
/* phyter seems to miss the mark by 16 ns */
#define ADJTIME_FIX 16
#if defined(__BIG_ENDIAN)
#define ENDIAN_FLAG 0
#elif defined(__LITTLE_ENDIAN)
#define ENDIAN_FLAG PSF_ENDIAN
#endif
#define SKB_PTP_TYPE(__skb) (*(unsigned int *)((__skb)->cb))
struct phy_rxts {
u16 ns_lo; /* ns[15:0] */
u16 ns_hi; /* overflow[1:0], ns[29:16] */
u16 sec_lo; /* sec[15:0] */
u16 sec_hi; /* sec[31:16] */
u16 seqid; /* sequenceId[15:0] */
u16 msgtype; /* messageType[3:0], hash[11:0] */
};
struct phy_txts {
u16 ns_lo; /* ns[15:0] */
u16 ns_hi; /* overflow[1:0], ns[29:16] */
u16 sec_lo; /* sec[15:0] */
u16 sec_hi; /* sec[31:16] */
};
struct rxts {
struct list_head list;
unsigned long tmo;
u64 ns;
u16 seqid;
u8 msgtype;
u16 hash;
};
struct dp83640_clock;
struct dp83640_private {
struct list_head list;
struct dp83640_clock *clock;
struct phy_device *phydev;
struct work_struct ts_work;
int hwts_tx_en;
int hwts_rx_en;
int layer;
int version;
/* remember state of cfg0 during calibration */
int cfg0;