ptp: clockmatrix: use rsmu driver to access i2c/spi bus
authorMin Li <min.li.xe@renesas.com>
Fri, 24 Sep 2021 19:01:32 +0000 (15:01 -0400)
committerDavid S. Miller <davem@davemloft.net>
Mon, 27 Sep 2021 11:16:48 +0000 (12:16 +0100)
rsmu (Renesas Synchronization Management Unit ) driver is located in
drivers/mfd and responsible for creating multiple devices including
clockmatrix phc, which will then use the exposed regmap and mutex
handle to access i2c/spi bus.

Signed-off-by: Min Li <min.li.xe@renesas.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/ptp/idt8a340_reg.h [deleted file]
drivers/ptp/ptp_clockmatrix.c
drivers/ptp/ptp_clockmatrix.h
include/linux/mfd/idt8a340_reg.h

diff --git a/drivers/ptp/idt8a340_reg.h b/drivers/ptp/idt8a340_reg.h
deleted file mode 100644 (file)
index 1c52101..0000000
+++ /dev/null
@@ -1,783 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/* idt8a340_reg.h
- *
- * Originally generated by regen.tcl on Thu Feb 14 19:23:44 PST 2019
- * https://github.com/richardcochran/regen
- *
- * Hand modified to include some HW registers.
- * Based on 5.2.0, Family Programming Guide (Sept 30, 2020)
- */
-#ifndef HAVE_IDT8A340_REG
-#define HAVE_IDT8A340_REG
-
-#define PAGE_ADDR_BASE                    0x0000
-#define PAGE_ADDR                         0x00fc
-
-#define HW_REVISION                       0x8180
-#define REV_ID                            0x007a
-
-#define HW_DPLL_0                         (0x8a00)
-#define HW_DPLL_1                         (0x8b00)
-#define HW_DPLL_2                         (0x8c00)
-#define HW_DPLL_3                         (0x8d00)
-#define HW_DPLL_4                         (0x8e00)
-#define HW_DPLL_5                         (0x8f00)
-#define HW_DPLL_6                         (0x9000)
-#define HW_DPLL_7                         (0x9100)
-
-#define HW_DPLL_TOD_SW_TRIG_ADDR__0       (0x080)
-#define HW_DPLL_TOD_CTRL_1                (0x089)
-#define HW_DPLL_TOD_CTRL_2                (0x08A)
-#define HW_DPLL_TOD_OVR__0                (0x098)
-#define HW_DPLL_TOD_OUT_0__0              (0x0B0)
-
-#define HW_Q0_Q1_CH_SYNC_CTRL_0           (0xa740)
-#define HW_Q0_Q1_CH_SYNC_CTRL_1           (0xa741)
-#define HW_Q2_Q3_CH_SYNC_CTRL_0           (0xa742)
-#define HW_Q2_Q3_CH_SYNC_CTRL_1           (0xa743)
-#define HW_Q4_Q5_CH_SYNC_CTRL_0           (0xa744)
-#define HW_Q4_Q5_CH_SYNC_CTRL_1           (0xa745)
-#define HW_Q6_Q7_CH_SYNC_CTRL_0           (0xa746)
-#define HW_Q6_Q7_CH_SYNC_CTRL_1           (0xa747)
-#define HW_Q8_CH_SYNC_CTRL_0              (0xa748)
-#define HW_Q8_CH_SYNC_CTRL_1              (0xa749)
-#define HW_Q9_CH_SYNC_CTRL_0              (0xa74a)
-#define HW_Q9_CH_SYNC_CTRL_1              (0xa74b)
-#define HW_Q10_CH_SYNC_CTRL_0             (0xa74c)
-#define HW_Q10_CH_SYNC_CTRL_1             (0xa74d)
-#define HW_Q11_CH_SYNC_CTRL_0             (0xa74e)
-#define HW_Q11_CH_SYNC_CTRL_1             (0xa74f)
-
-#define SYNC_SOURCE_DPLL0_TOD_PPS      0x14
-#define SYNC_SOURCE_DPLL1_TOD_PPS      0x15
-#define SYNC_SOURCE_DPLL2_TOD_PPS      0x16
-#define SYNC_SOURCE_DPLL3_TOD_PPS      0x17
-
-#define SYNCTRL1_MASTER_SYNC_RST       BIT(7)
-#define SYNCTRL1_MASTER_SYNC_TRIG      BIT(5)
-#define SYNCTRL1_TOD_SYNC_TRIG         BIT(4)
-#define SYNCTRL1_FBDIV_FRAME_SYNC_TRIG BIT(3)
-#define SYNCTRL1_FBDIV_SYNC_TRIG       BIT(2)
-#define SYNCTRL1_Q1_DIV_SYNC_TRIG      BIT(1)
-#define SYNCTRL1_Q0_DIV_SYNC_TRIG      BIT(0)
-
-#define HW_Q8_CTRL_SPARE  (0xa7d4)
-#define HW_Q11_CTRL_SPARE (0xa7ec)
-
-/**
- * Select FOD5 as sync_trigger for Q8 divider.
- * Transition from logic zero to one
- * sets trigger to sync Q8 divider.
- *
- * Unused when FOD4 is driving Q8 divider (normal operation).
- */
-#define Q9_TO_Q8_SYNC_TRIG  BIT(1)
-
-/**
- * Enable FOD5 as driver for clock and sync for Q8 divider.
- * Enable fanout buffer for FOD5.
- *
- * Unused when FOD4 is driving Q8 divider (normal operation).
- */
-#define Q9_TO_Q8_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK  (BIT(0) | BIT(2))
-
-/**
- * Select FOD6 as sync_trigger for Q11 divider.
- * Transition from logic zero to one
- * sets trigger to sync Q11 divider.
- *
- * Unused when FOD7 is driving Q11 divider (normal operation).
- */
-#define Q10_TO_Q11_SYNC_TRIG  BIT(1)
-
-/**
- * Enable FOD6 as driver for clock and sync for Q11 divider.
- * Enable fanout buffer for FOD6.
- *
- * Unused when FOD7 is driving Q11 divider (normal operation).
- */
-#define Q10_TO_Q11_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK  (BIT(0) | BIT(2))
-
-#define RESET_CTRL                        0xc000
-#define SM_RESET                          0x0012
-#define SM_RESET_V520                     0x0013
-#define SM_RESET_CMD                      0x5A
-
-#define GENERAL_STATUS                    0xc014
-#define BOOT_STATUS                       0x0000
-#define HW_REV_ID                         0x000A
-#define BOND_ID                           0x000B
-#define HW_CSR_ID                         0x000C
-#define HW_IRQ_ID                         0x000E
-
-#define MAJ_REL                           0x0010
-#define MIN_REL                           0x0011
-#define HOTFIX_REL                        0x0012
-
-#define PIPELINE_ID                       0x0014
-#define BUILD_ID                          0x0018
-
-#define JTAG_DEVICE_ID                    0x001c
-#define PRODUCT_ID                        0x001e
-
-#define OTP_SCSR_CONFIG_SELECT            0x0022
-
-#define STATUS                            0xc03c
-#define DPLL_SYS_STATUS                   0x0020
-#define DPLL_SYS_APLL_STATUS              0x0021
-#define USER_GPIO0_TO_7_STATUS            0x008a
-#define USER_GPIO8_TO_15_STATUS           0x008b
-
-#define GPIO_USER_CONTROL                 0xc160
-#define GPIO0_TO_7_OUT                    0x0000
-#define GPIO8_TO_15_OUT                   0x0001
-#define GPIO0_TO_7_OUT_V520               0x0002
-#define GPIO8_TO_15_OUT_V520              0x0003
-
-#define STICKY_STATUS_CLEAR               0xc164
-
-#define GPIO_TOD_NOTIFICATION_CLEAR       0xc16c
-
-#define ALERT_CFG                         0xc188
-
-#define SYS_DPLL_XO                       0xc194
-
-#define SYS_APLL                          0xc19c
-
-#define INPUT_0                           0xc1b0
-
-#define INPUT_1                           0xc1c0
-
-#define INPUT_2                           0xc1d0
-
-#define INPUT_3                           0xc200
-
-#define INPUT_4                           0xc210
-
-#define INPUT_5                           0xc220
-
-#define INPUT_6                           0xc230
-
-#define INPUT_7                           0xc240
-
-#define INPUT_8                           0xc250
-
-#define INPUT_9                           0xc260
-
-#define INPUT_10                          0xc280
-
-#define INPUT_11                          0xc290
-
-#define INPUT_12                          0xc2a0
-
-#define INPUT_13                          0xc2b0
-
-#define INPUT_14                          0xc2c0
-
-#define INPUT_15                          0xc2d0
-
-#define REF_MON_0                         0xc2e0
-
-#define REF_MON_1                         0xc2ec
-
-#define REF_MON_2                         0xc300
-
-#define REF_MON_3                         0xc30c
-
-#define REF_MON_4                         0xc318
-
-#define REF_MON_5                         0xc324
-
-#define REF_MON_6                         0xc330
-
-#define REF_MON_7                         0xc33c
-
-#define REF_MON_8                         0xc348
-
-#define REF_MON_9                         0xc354
-
-#define REF_MON_10                        0xc360
-
-#define REF_MON_11                        0xc36c
-
-#define REF_MON_12                        0xc380
-
-#define REF_MON_13                        0xc38c
-
-#define REF_MON_14                        0xc398
-
-#define REF_MON_15                        0xc3a4
-
-#define DPLL_0                            0xc3b0
-#define DPLL_CTRL_REG_0                   0x0002
-#define DPLL_CTRL_REG_1                   0x0003
-#define DPLL_CTRL_REG_2                   0x0004
-#define DPLL_TOD_SYNC_CFG                 0x0031
-#define DPLL_COMBO_SLAVE_CFG_0            0x0032
-#define DPLL_COMBO_SLAVE_CFG_1            0x0033
-#define DPLL_SLAVE_REF_CFG                0x0034
-#define DPLL_REF_MODE                     0x0035
-#define DPLL_PHASE_MEASUREMENT_CFG        0x0036
-#define DPLL_MODE                         0x0037
-#define DPLL_MODE_V520                    0x003B
-
-#define DPLL_1                            0xc400
-
-#define DPLL_2                            0xc438
-#define DPLL_2_V520                       0xc43c
-
-#define DPLL_3                            0xc480
-
-#define DPLL_4                            0xc4b8
-#define DPLL_4_V520                       0xc4bc
-
-#define DPLL_5                            0xc500
-
-#define DPLL_6                            0xc538
-#define DPLL_6_V520                       0xc53c
-
-#define DPLL_7                            0xc580
-
-#define SYS_DPLL                          0xc5b8
-#define SYS_DPLL_V520                     0xc5bc
-
-#define DPLL_CTRL_0                       0xc600
-#define DPLL_CTRL_DPLL_MANU_REF_CFG       0x0001
-#define DPLL_CTRL_COMBO_MASTER_CFG        0x003a
-
-#define DPLL_CTRL_1                       0xc63c
-
-#define DPLL_CTRL_2                       0xc680
-
-#define DPLL_CTRL_3                       0xc6bc
-
-#define DPLL_CTRL_4                       0xc700
-
-#define DPLL_CTRL_5                       0xc73c
-
-#define DPLL_CTRL_6                       0xc780
-
-#define DPLL_CTRL_7                       0xc7bc
-
-#define SYS_DPLL_CTRL                     0xc800
-
-#define DPLL_PHASE_0                      0xc818
-
-/* Signed 42-bit FFO in units of 2^(-53) */
-#define DPLL_WR_PHASE                     0x0000
-
-#define DPLL_PHASE_1                      0xc81c
-
-#define DPLL_PHASE_2                      0xc820
-
-#define DPLL_PHASE_3                      0xc824
-
-#define DPLL_PHASE_4                      0xc828
-
-#define DPLL_PHASE_5                      0xc82c
-
-#define DPLL_PHASE_6                      0xc830
-
-#define DPLL_PHASE_7                      0xc834
-
-#define DPLL_FREQ_0                       0xc838
-
-/* Signed 42-bit FFO in units of 2^(-53) */
-#define DPLL_WR_FREQ                      0x0000
-
-#define DPLL_FREQ_1                       0xc840
-
-#define DPLL_FREQ_2                       0xc848
-
-#define DPLL_FREQ_3                       0xc850
-
-#define DPLL_FREQ_4                       0xc858
-
-#define DPLL_FREQ_5                       0xc860
-
-#define DPLL_FREQ_6                       0xc868
-
-#define DPLL_FREQ_7                       0xc870
-
-#define DPLL_PHASE_PULL_IN_0              0xc880
-#define PULL_IN_OFFSET                    0x0000 /* Signed 32 bit */
-#define PULL_IN_SLOPE_LIMIT               0x0004 /* Unsigned 24 bit */
-#define PULL_IN_CTRL                      0x0007
-
-#define DPLL_PHASE_PULL_IN_1              0xc888
-
-#define DPLL_PHASE_PULL_IN_2              0xc890
-
-#define DPLL_PHASE_PULL_IN_3              0xc898
-
-#define DPLL_PHASE_PULL_IN_4              0xc8a0
-
-#define DPLL_PHASE_PULL_IN_5              0xc8a8
-
-#define DPLL_PHASE_PULL_IN_6              0xc8b0
-
-#define DPLL_PHASE_PULL_IN_7              0xc8b8
-
-#define GPIO_CFG                          0xc8c0
-#define GPIO_CFG_GBL                      0x0000
-
-#define GPIO_0                            0xc8c2
-#define GPIO_DCO_INC_DEC                  0x0000
-#define GPIO_OUT_CTRL_0                   0x0001
-#define GPIO_OUT_CTRL_1                   0x0002
-#define GPIO_TOD_TRIG                     0x0003
-#define GPIO_DPLL_INDICATOR               0x0004
-#define GPIO_LOS_INDICATOR                0x0005
-#define GPIO_REF_INPUT_DSQ_0              0x0006
-#define GPIO_REF_INPUT_DSQ_1              0x0007
-#define GPIO_REF_INPUT_DSQ_2              0x0008
-#define GPIO_REF_INPUT_DSQ_3              0x0009
-#define GPIO_MAN_CLK_SEL_0                0x000a
-#define GPIO_MAN_CLK_SEL_1                0x000b
-#define GPIO_MAN_CLK_SEL_2                0x000c
-#define GPIO_SLAVE                        0x000d
-#define GPIO_ALERT_OUT_CFG                0x000e
-#define GPIO_TOD_NOTIFICATION_CFG         0x000f
-#define GPIO_CTRL                         0x0010
-#define GPIO_CTRL_V520                    0x0011
-
-#define GPIO_1                            0xc8d4
-
-#define GPIO_2                            0xc8e6
-
-#define GPIO_3                            0xc900
-
-#define GPIO_4                            0xc912
-
-#define GPIO_5                            0xc924
-
-#define GPIO_6                            0xc936
-
-#define GPIO_7                            0xc948
-
-#define GPIO_8                            0xc95a
-
-#define GPIO_9                            0xc980
-
-#define GPIO_10                           0xc992
-
-#define GPIO_11                           0xc9a4
-
-#define GPIO_12                           0xc9b6
-
-#define GPIO_13                           0xc9c8
-
-#define GPIO_14                           0xc9da
-
-#define GPIO_15                           0xca00
-
-#define OUT_DIV_MUX                       0xca12
-
-#define OUTPUT_0                          0xca14
-#define OUTPUT_0_V520                     0xca20
-/* FOD frequency output divider value */
-#define OUT_DIV                           0x0000
-#define OUT_DUTY_CYCLE_HIGH               0x0004
-#define OUT_CTRL_0                        0x0008
-#define OUT_CTRL_1                        0x0009
-/* Phase adjustment in FOD cycles */
-#define OUT_PHASE_ADJ                     0x000c
-
-#define OUTPUT_1                          0xca24
-#define OUTPUT_1_V520                     0xca30
-
-#define OUTPUT_2                          0xca34
-#define OUTPUT_2_V520                     0xca40
-
-#define OUTPUT_3                          0xca44
-#define OUTPUT_3_V520                     0xca50
-
-#define OUTPUT_4                          0xca54
-#define OUTPUT_4_V520                     0xca60
-
-#define OUTPUT_5                          0xca64
-#define OUTPUT_5_V520                     0xca80
-
-#define OUTPUT_6                          0xca80
-#define OUTPUT_6_V520                     0xca90
-
-#define OUTPUT_7                          0xca90
-#define OUTPUT_7_V520                     0xcaa0
-
-#define OUTPUT_8                          0xcaa0
-#define OUTPUT_8_V520                     0xcab0
-
-#define OUTPUT_9                          0xcab0
-#define OUTPUT_9_V520                     0xcac0
-
-#define OUTPUT_10                         0xcac0
-#define OUTPUT_10_V520                     0xcad0
-
-#define OUTPUT_11                         0xcad0
-#define OUTPUT_11_V520                    0xcae0
-
-#define SERIAL                            0xcae0
-#define SERIAL_V520                       0xcaf0
-
-#define PWM_ENCODER_0                     0xcb00
-
-#define PWM_ENCODER_1                     0xcb08
-
-#define PWM_ENCODER_2                     0xcb10
-
-#define PWM_ENCODER_3                     0xcb18
-
-#define PWM_ENCODER_4                     0xcb20
-
-#define PWM_ENCODER_5                     0xcb28
-
-#define PWM_ENCODER_6                     0xcb30
-
-#define PWM_ENCODER_7                     0xcb38
-
-#define PWM_DECODER_0                     0xcb40
-
-#define PWM_DECODER_1                     0xcb48
-#define PWM_DECODER_1_V520                0xcb4a
-
-#define PWM_DECODER_2                     0xcb50
-#define PWM_DECODER_2_V520                0xcb54
-
-#define PWM_DECODER_3                     0xcb58
-#define PWM_DECODER_3_V520                0xcb5e
-
-#define PWM_DECODER_4                     0xcb60
-#define PWM_DECODER_4_V520                0xcb68
-
-#define PWM_DECODER_5                     0xcb68
-#define PWM_DECODER_5_V520                0xcb80
-
-#define PWM_DECODER_6                     0xcb70
-#define PWM_DECODER_6_V520                0xcb8a
-
-#define PWM_DECODER_7                     0xcb80
-#define PWM_DECODER_7_V520                0xcb94
-
-#define PWM_DECODER_8                     0xcb88
-#define PWM_DECODER_8_V520                0xcb9e
-
-#define PWM_DECODER_9                     0xcb90
-#define PWM_DECODER_9_V520                0xcba8
-
-#define PWM_DECODER_10                    0xcb98
-#define PWM_DECODER_10_V520               0xcbb2
-
-#define PWM_DECODER_11                    0xcba0
-#define PWM_DECODER_11_V520               0xcbbc
-
-#define PWM_DECODER_12                    0xcba8
-#define PWM_DECODER_12_V520               0xcbc6
-
-#define PWM_DECODER_13                    0xcbb0
-#define PWM_DECODER_13_V520               0xcbd0
-
-#define PWM_DECODER_14                    0xcbb8
-#define PWM_DECODER_14_V520               0xcbda
-
-#define PWM_DECODER_15                    0xcbc0
-#define PWM_DECODER_15_V520               0xcbe4
-
-#define PWM_USER_DATA                     0xcbc8
-#define PWM_USER_DATA_V520                0xcbf0
-
-#define TOD_0                             0xcbcc
-#define TOD_0_V520                        0xcc00
-
-/* Enable TOD counter, output channel sync and even-PPS mode */
-#define TOD_CFG                           0x0000
-#define TOD_CFG_V520                      0x0001
-
-#define TOD_1                             0xcbce
-#define TOD_1_V520                        0xcc02
-
-#define TOD_2                             0xcbd0
-#define TOD_2_V520                        0xcc04
-
-#define TOD_3                             0xcbd2
-#define TOD_3_V520                        0xcc06
-
-
-#define TOD_WRITE_0                       0xcc00
-#define TOD_WRITE_0_V520                  0xcc10
-/* 8-bit subns, 32-bit ns, 48-bit seconds */
-#define TOD_WRITE                         0x0000
-/* Counter increments after TOD write is completed */
-#define TOD_WRITE_COUNTER                 0x000c
-/* TOD write trigger configuration */
-#define TOD_WRITE_SELECT_CFG_0            0x000d
-/* TOD write trigger selection */
-#define TOD_WRITE_CMD                     0x000f
-
-#define TOD_WRITE_1                       0xcc10
-#define TOD_WRITE_1_V520                  0xcc20
-
-#define TOD_WRITE_2                       0xcc20
-#define TOD_WRITE_2_V520                  0xcc30
-
-#define TOD_WRITE_3                       0xcc30
-#define TOD_WRITE_3_V520                  0xcc40
-
-#define TOD_READ_PRIMARY_0                0xcc40
-#define TOD_READ_PRIMARY_0_V520           0xcc50
-/* 8-bit subns, 32-bit ns, 48-bit seconds */
-#define TOD_READ_PRIMARY                  0x0000
-/* Counter increments after TOD write is completed */
-#define TOD_READ_PRIMARY_COUNTER          0x000b
-/* Read trigger configuration */
-#define TOD_READ_PRIMARY_SEL_CFG_0        0x000c
-/* Read trigger selection */
-#define TOD_READ_PRIMARY_CMD              0x000e
-#define TOD_READ_PRIMARY_CMD_V520         0x000f
-
-#define TOD_READ_PRIMARY_1                0xcc50
-#define TOD_READ_PRIMARY_1_V520           0xcc60
-
-#define TOD_READ_PRIMARY_2                0xcc60
-#define TOD_READ_PRIMARY_2_V520           0xcc80
-
-#define TOD_READ_PRIMARY_3                0xcc80
-#define TOD_READ_PRIMARY_3_V520           0xcc90
-
-#define TOD_READ_SECONDARY_0              0xcc90
-#define TOD_READ_SECONDARY_0_V520         0xcca0
-
-#define TOD_READ_SECONDARY_1              0xcca0
-#define TOD_READ_SECONDARY_1_V520         0xccb0
-
-#define TOD_READ_SECONDARY_2              0xccb0
-#define TOD_READ_SECONDARY_2_V520         0xccc0
-
-#define TOD_READ_SECONDARY_3              0xccc0
-#define TOD_READ_SECONDARY_3_V520         0xccd0
-
-#define OUTPUT_TDC_CFG                    0xccd0
-#define OUTPUT_TDC_CFG_V520               0xcce0
-
-#define OUTPUT_TDC_0                      0xcd00
-
-#define OUTPUT_TDC_1                      0xcd08
-
-#define OUTPUT_TDC_2                      0xcd10
-
-#define OUTPUT_TDC_3                      0xcd18
-
-#define INPUT_TDC                         0xcd20
-
-#define SCRATCH                           0xcf50
-#define SCRATCH_V520                      0xcf4c
-
-#define EEPROM                            0xcf68
-#define EEPROM_V520                       0xcf64
-
-#define OTP                               0xcf70
-
-#define BYTE                              0xcf80
-
-/* Bit definitions for the MAJ_REL register */
-#define MAJOR_SHIFT                       (1)
-#define MAJOR_MASK                        (0x7f)
-#define PR_BUILD                          BIT(0)
-
-/* Bit definitions for the USER_GPIO0_TO_7_STATUS register */
-#define GPIO0_LEVEL                       BIT(0)
-#define GPIO1_LEVEL                       BIT(1)
-#define GPIO2_LEVEL                       BIT(2)
-#define GPIO3_LEVEL                       BIT(3)
-#define GPIO4_LEVEL                       BIT(4)
-#define GPIO5_LEVEL                       BIT(5)
-#define GPIO6_LEVEL                       BIT(6)
-#define GPIO7_LEVEL                       BIT(7)
-
-/* Bit definitions for the USER_GPIO8_TO_15_STATUS register */
-#define GPIO8_LEVEL                       BIT(0)
-#define GPIO9_LEVEL                       BIT(1)
-#define GPIO10_LEVEL                      BIT(2)
-#define GPIO11_LEVEL                      BIT(3)
-#define GPIO12_LEVEL                      BIT(4)
-#define GPIO13_LEVEL                      BIT(5)
-#define GPIO14_LEVEL                      BIT(6)
-#define GPIO15_LEVEL                      BIT(7)
-
-/* Bit definitions for the GPIO0_TO_7_OUT register */
-#define GPIO0_DRIVE_LEVEL                 BIT(0)
-#define GPIO1_DRIVE_LEVEL                 BIT(1)
-#define GPIO2_DRIVE_LEVEL                 BIT(2)
-#define GPIO3_DRIVE_LEVEL                 BIT(3)
-#define GPIO4_DRIVE_LEVEL                 BIT(4)
-#define GPIO5_DRIVE_LEVEL                 BIT(5)
-#define GPIO6_DRIVE_LEVEL                 BIT(6)
-#define GPIO7_DRIVE_LEVEL                 BIT(7)
-
-/* Bit definitions for the GPIO8_TO_15_OUT register */
-#define GPIO8_DRIVE_LEVEL                 BIT(0)
-#define GPIO9_DRIVE_LEVEL                 BIT(1)
-#define GPIO10_DRIVE_LEVEL                BIT(2)
-#define GPIO11_DRIVE_LEVEL                BIT(3)
-#define GPIO12_DRIVE_LEVEL                BIT(4)
-#define GPIO13_DRIVE_LEVEL                BIT(5)
-#define GPIO14_DRIVE_LEVEL                BIT(6)
-#define GPIO15_DRIVE_LEVEL                BIT(7)
-
-/* Bit definitions for the DPLL_TOD_SYNC_CFG register */
-#define TOD_SYNC_SOURCE_SHIFT             (1)
-#define TOD_SYNC_SOURCE_MASK              (0x3)
-#define TOD_SYNC_EN                       BIT(0)
-
-/* Bit definitions for the DPLL_MODE register */
-#define WRITE_TIMER_MODE                  BIT(6)
-#define PLL_MODE_SHIFT                    (3)
-#define PLL_MODE_MASK                     (0x7)
-#define STATE_MODE_SHIFT                  (0)
-#define STATE_MODE_MASK                   (0x7)
-
-/* Bit definitions for the DPLL_MANU_REF_CFG register */
-#define MANUAL_REFERENCE_SHIFT            (0)
-#define MANUAL_REFERENCE_MASK             (0x1f)
-
-/* Bit definitions for the GPIO_CFG_GBL register */
-#define SUPPLY_MODE_SHIFT                 (0)
-#define SUPPLY_MODE_MASK                  (0x3)
-
-/* Bit definitions for the GPIO_DCO_INC_DEC register */
-#define INCDEC_DPLL_INDEX_SHIFT           (0)
-#define INCDEC_DPLL_INDEX_MASK            (0x7)
-
-/* Bit definitions for the GPIO_OUT_CTRL_0 register */
-#define CTRL_OUT_0                        BIT(0)
-#define CTRL_OUT_1                        BIT(1)
-#define CTRL_OUT_2                        BIT(2)
-#define CTRL_OUT_3                        BIT(3)
-#define CTRL_OUT_4                        BIT(4)
-#define CTRL_OUT_5                        BIT(5)
-#define CTRL_OUT_6                        BIT(6)
-#define CTRL_OUT_7                        BIT(7)
-
-/* Bit definitions for the GPIO_OUT_CTRL_1 register */
-#define CTRL_OUT_8                        BIT(0)
-#define CTRL_OUT_9                        BIT(1)
-#define CTRL_OUT_10                       BIT(2)
-#define CTRL_OUT_11                       BIT(3)
-#define CTRL_OUT_12                       BIT(4)
-#define CTRL_OUT_13                       BIT(5)
-#define CTRL_OUT_14                       BIT(6)
-#define CTRL_OUT_15                       BIT(7)
-
-/* Bit definitions for the GPIO_TOD_TRIG register */
-#define TOD_TRIG_0                        BIT(0)
-#define TOD_TRIG_1                        BIT(1)
-#define TOD_TRIG_2                        BIT(2)
-#define TOD_TRIG_3                        BIT(3)
-
-/* Bit definitions for the GPIO_DPLL_INDICATOR register */
-#define IND_DPLL_INDEX_SHIFT              (0)
-#define IND_DPLL_INDEX_MASK               (0x7)
-
-/* Bit definitions for the GPIO_LOS_INDICATOR register */
-#define REFMON_INDEX_SHIFT                (0)
-#define REFMON_INDEX_MASK                 (0xf)
-/* Active level of LOS indicator, 0=low 1=high */
-#define ACTIVE_LEVEL                      BIT(4)
-
-/* Bit definitions for the GPIO_REF_INPUT_DSQ_0 register */
-#define DSQ_INP_0                         BIT(0)
-#define DSQ_INP_1                         BIT(1)
-#define DSQ_INP_2                         BIT(2)
-#define DSQ_INP_3                         BIT(3)
-#define DSQ_INP_4                         BIT(4)
-#define DSQ_INP_5                         BIT(5)
-#define DSQ_INP_6                         BIT(6)
-#define DSQ_INP_7                         BIT(7)
-
-/* Bit definitions for the GPIO_REF_INPUT_DSQ_1 register */
-#define DSQ_INP_8                         BIT(0)
-#define DSQ_INP_9                         BIT(1)
-#define DSQ_INP_10                        BIT(2)
-#define DSQ_INP_11                        BIT(3)
-#define DSQ_INP_12                        BIT(4)
-#define DSQ_INP_13                        BIT(5)
-#define DSQ_INP_14                        BIT(6)
-#define DSQ_INP_15                        BIT(7)
-
-/* Bit definitions for the GPIO_REF_INPUT_DSQ_2 register */
-#define DSQ_DPLL_0                        BIT(0)
-#define DSQ_DPLL_1                        BIT(1)
-#define DSQ_DPLL_2                        BIT(2)
-#define DSQ_DPLL_3                        BIT(3)
-#define DSQ_DPLL_4                        BIT(4)
-#define DSQ_DPLL_5                        BIT(5)
-#define DSQ_DPLL_6                        BIT(6)
-#define DSQ_DPLL_7                        BIT(7)
-
-/* Bit definitions for the GPIO_REF_INPUT_DSQ_3 register */
-#define DSQ_DPLL_SYS                      BIT(0)
-#define GPIO_DSQ_LEVEL                    BIT(1)
-
-/* Bit definitions for the GPIO_TOD_NOTIFICATION_CFG register */
-#define DPLL_TOD_SHIFT                    (0)
-#define DPLL_TOD_MASK                     (0x3)
-#define TOD_READ_SECONDARY                BIT(2)
-#define GPIO_ASSERT_LEVEL                 BIT(3)
-
-/* Bit definitions for the GPIO_CTRL register */
-#define GPIO_FUNCTION_EN                  BIT(0)
-#define GPIO_CMOS_OD_MODE                 BIT(1)
-#define GPIO_CONTROL_DIR                  BIT(2)
-#define GPIO_PU_PD_MODE                   BIT(3)
-#define GPIO_FUNCTION_SHIFT               (4)
-#define GPIO_FUNCTION_MASK                (0xf)
-
-/* Bit definitions for the OUT_CTRL_1 register */
-#define OUT_SYNC_DISABLE                  BIT(7)
-#define SQUELCH_VALUE                     BIT(6)
-#define SQUELCH_DISABLE                   BIT(5)
-#define PAD_VDDO_SHIFT                    (2)
-#define PAD_VDDO_MASK                     (0x7)
-#define PAD_CMOSDRV_SHIFT                 (0)
-#define PAD_CMOSDRV_MASK                  (0x3)
-
-/* Bit definitions for the TOD_CFG register */
-#define TOD_EVEN_PPS_MODE                 BIT(2)
-#define TOD_OUT_SYNC_ENABLE               BIT(1)
-#define TOD_ENABLE                        BIT(0)
-
-/* Bit definitions for the TOD_WRITE_SELECT_CFG_0 register */
-#define WR_PWM_DECODER_INDEX_SHIFT        (4)
-#define WR_PWM_DECODER_INDEX_MASK         (0xf)
-#define WR_REF_INDEX_SHIFT                (0)
-#define WR_REF_INDEX_MASK                 (0xf)
-
-/* Bit definitions for the TOD_WRITE_CMD register */
-#define TOD_WRITE_SELECTION_SHIFT         (0)
-#define TOD_WRITE_SELECTION_MASK          (0xf)
-/* 4.8.7 */
-#define TOD_WRITE_TYPE_SHIFT              (4)
-#define TOD_WRITE_TYPE_MASK               (0x3)
-
-/* Bit definitions for the TOD_READ_PRIMARY_SEL_CFG_0 register */
-#define RD_PWM_DECODER_INDEX_SHIFT        (4)
-#define RD_PWM_DECODER_INDEX_MASK         (0xf)
-#define RD_REF_INDEX_SHIFT                (0)
-#define RD_REF_INDEX_MASK                 (0xf)
-
-/* Bit definitions for the TOD_READ_PRIMARY_CMD register */
-#define TOD_READ_TRIGGER_MODE             BIT(4)
-#define TOD_READ_TRIGGER_SHIFT            (0)
-#define TOD_READ_TRIGGER_MASK             (0xf)
-
-/* Bit definitions for the DPLL_CTRL_COMBO_MASTER_CFG register */
-#define COMBO_MASTER_HOLD                 BIT(0)
-
-/* Bit definitions for DPLL_SYS_STATUS register */
-#define DPLL_SYS_STATE_MASK               (0xf)
-
-/* Bit definitions for SYS_APLL_STATUS register */
-#define SYS_APLL_LOSS_LOCK_LIVE_MASK       BIT(0)
-#define SYS_APLL_LOSS_LOCK_LIVE_LOCKED     0
-#define SYS_APLL_LOSS_LOCK_LIVE_UNLOCKED   1
-
-#endif
index 1a2e3c2..6bc5791 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright (C) 2019 Integrated Device Technology, Inc., a Renesas Company.
  */
 #include <linux/firmware.h>
-#include <linux/i2c.h>
+#include <linux/platform_device.h>
 #include <linux/module.h>
 #include <linux/ptp_clock_kernel.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/timekeeping.h>
 #include <linux/string.h>
+#include <linux/of.h>
+#include <linux/mfd/rsmu.h>
+#include <linux/mfd/idt8a340_reg.h>
+#include <asm/unaligned.h>
 
 #include "ptp_private.h"
 #include "ptp_clockmatrix.h"
@@ -32,9 +36,28 @@ static char *firmware;
 module_param(firmware, charp, 0);
 
 #define SETTIME_CORRECTION (0)
+#define EXTTS_PERIOD_MS (95)
 
 static int _idtcm_adjfine(struct idtcm_channel *channel, long scaled_ppm);
 
+static inline int idtcm_read(struct idtcm *idtcm,
+                            u16 module,
+                            u16 regaddr,
+                            u8 *buf,
+                            u16 count)
+{
+       return regmap_bulk_read(idtcm->regmap, module + regaddr, buf, count);
+}
+
+static inline int idtcm_write(struct idtcm *idtcm,
+                             u16 module,
+                             u16 regaddr,
+                             u8 *buf,
+                             u16 count)
+{
+       return regmap_bulk_write(idtcm->regmap, module + regaddr, buf, count);
+}
+
 static int contains_full_configuration(struct idtcm *idtcm,
                                       const struct firmware *fw)
 {
@@ -173,134 +196,6 @@ static enum fw_version idtcm_fw_version(const char *version)
        return ver;
 }
 
-static int idtcm_xfer_read(struct idtcm *idtcm,
-                          u8 regaddr,
-                          u8 *buf,
-                          u16 count)
-{
-       struct i2c_client *client = idtcm->client;
-       struct i2c_msg msg[2];
-       int cnt;
-
-       msg[0].addr = client->addr;
-       msg[0].flags = 0;
-       msg[0].len = 1;
-       msg[0].buf = &regaddr;
-
-       msg[1].addr = client->addr;
-       msg[1].flags = I2C_M_RD;
-       msg[1].len = count;
-       msg[1].buf = buf;
-
-       cnt = i2c_transfer(client->adapter, msg, 2);
-
-       if (cnt < 0) {
-               dev_err(&client->dev,
-                       "i2c_transfer failed at %d in %s, at addr: %04x!",
-                       __LINE__, __func__, regaddr);
-               return cnt;
-       } else if (cnt != 2) {
-               dev_err(&client->dev,
-                       "i2c_transfer sent only %d of %d messages", cnt, 2);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int idtcm_xfer_write(struct idtcm *idtcm,
-                           u8 regaddr,
-                           u8 *buf,
-                           u16 count)
-{
-       struct i2c_client *client = idtcm->client;
-       /* we add 1 byte for device register */
-       u8 msg[IDTCM_MAX_WRITE_COUNT + 1];
-       int cnt;
-
-       if (count > IDTCM_MAX_WRITE_COUNT)
-               return -EINVAL;
-
-       msg[0] = regaddr;
-       memcpy(&msg[1], buf, count);
-
-       cnt = i2c_master_send(client, msg, count + 1);
-
-       if (cnt < 0) {
-               dev_err(&client->dev,
-                       "i2c_master_send failed at %d in %s, at addr: %04x!",
-                       __LINE__, __func__, regaddr);
-               return cnt;
-       }
-
-       return 0;
-}
-
-static int idtcm_page_offset(struct idtcm *idtcm, u8 val)
-{
-       u8 buf[4];
-       int err;
-
-       if (idtcm->page_offset == val)
-               return 0;
-
-       buf[0] = 0x0;
-       buf[1] = val;
-       buf[2] = 0x10;
-       buf[3] = 0x20;
-
-       err = idtcm_xfer_write(idtcm, PAGE_ADDR, buf, sizeof(buf));
-       if (err) {
-               idtcm->page_offset = 0xff;
-               dev_err(&idtcm->client->dev, "failed to set page offset");
-       } else {
-               idtcm->page_offset = val;
-       }
-
-       return err;
-}
-
-static int _idtcm_rdwr(struct idtcm *idtcm,
-                      u16 regaddr,
-                      u8 *buf,
-                      u16 count,
-                      bool write)
-{
-       u8 hi;
-       u8 lo;
-       int err;
-
-       hi = (regaddr >> 8) & 0xff;
-       lo = regaddr & 0xff;
-
-       err = idtcm_page_offset(idtcm, hi);
-       if (err)
-               return err;
-
-       if (write)
-               return idtcm_xfer_write(idtcm, lo, buf, count);
-
-       return idtcm_xfer_read(idtcm, lo, buf, count);
-}
-
-static int idtcm_read(struct idtcm *idtcm,
-                     u16 module,
-                     u16 regaddr,
-                     u8 *buf,
-                     u16 count)
-{
-       return _idtcm_rdwr(idtcm, module + regaddr, buf, count, false);
-}
-
-static int idtcm_write(struct idtcm *idtcm,
-                      u16 module,
-                      u16 regaddr,
-                      u8 *buf,
-                      u16 count)
-{
-       return _idtcm_rdwr(idtcm, module + regaddr, buf, count, true);
-}
-
 static int clear_boot_status(struct idtcm *idtcm)
 {
        u8 buf[4] = {0};
@@ -339,11 +234,82 @@ static int wait_for_boot_status_ready(struct idtcm *idtcm)
 
        } while (i);
 
-       dev_warn(&idtcm->client->dev, "%s timed out", __func__);
+       dev_warn(idtcm->dev, "%s timed out", __func__);
 
        return -EBUSY;
 }
 
+static int _idtcm_set_scsr_read_trig(struct idtcm_channel *channel,
+                                    enum scsr_read_trig_sel trig, u8 ref)
+{
+       struct idtcm *idtcm = channel->idtcm;
+       u16 tod_read_cmd = IDTCM_FW_REG(idtcm->fw_ver, V520, TOD_READ_PRIMARY_CMD);
+       u8 val;
+       int err;
+
+       if (trig == SCSR_TOD_READ_TRIG_SEL_REFCLK) {
+               err = idtcm_read(idtcm, channel->tod_read_primary,
+                                TOD_READ_PRIMARY_SEL_CFG_0, &val, sizeof(val));
+               if (err)
+                       return err;
+
+               val &= ~(WR_REF_INDEX_MASK << WR_REF_INDEX_SHIFT);
+               val |= (ref << WR_REF_INDEX_SHIFT);
+
+               err = idtcm_write(idtcm, channel->tod_read_primary,
+                                 TOD_READ_PRIMARY_SEL_CFG_0, &val, sizeof(val));
+               if (err)
+                       return err;
+       }
+
+       err = idtcm_read(idtcm, channel->tod_read_primary,
+                        tod_read_cmd, &val, sizeof(val));
+       if (err)
+               return err;
+
+       val &= ~(TOD_READ_TRIGGER_MASK << TOD_READ_TRIGGER_SHIFT);
+       val |= (trig << TOD_READ_TRIGGER_SHIFT);
+       val &= ~TOD_READ_TRIGGER_MODE; /* single shot */
+
+       err = idtcm_write(idtcm, channel->tod_read_primary,
+                         tod_read_cmd, &val, sizeof(val));
+       return err;
+}
+
+static int idtcm_enable_extts(struct idtcm_channel *channel, u8 todn, u8 ref,
+                             bool enable)
+{
+       struct idtcm *idtcm = channel->idtcm;
+       u8 old_mask = idtcm->extts_mask;
+       u8 mask = 1 << todn;
+       int err = 0;
+
+       if (todn >= MAX_TOD)
+               return -EINVAL;
+
+       if (enable) {
+               if (ref > 0xF) /* E_REF_CLK15 */
+                       return -EINVAL;
+               if (idtcm->extts_mask & mask)
+                       return 0;
+               err = _idtcm_set_scsr_read_trig(&idtcm->channel[todn],
+                                               SCSR_TOD_READ_TRIG_SEL_REFCLK,
+                                               ref);
+               if (err == 0) {
+                       idtcm->extts_mask |= mask;
+                       idtcm->event_channel[todn] = channel;
+                       idtcm->channel[todn].refn = ref;
+               }
+       } else
+               idtcm->extts_mask &= ~mask;
+
+       if (old_mask == 0 && idtcm->extts_mask)
+               schedule_delayed_work(&idtcm->extts_work,
+                                     msecs_to_jiffies(EXTTS_PERIOD_MS));
+
+       return err;
+}
+
 static int read_sys_apll_status(struct idtcm *idtcm, u8 *status)
 {
        return idtcm_read(idtcm, STATUS, DPLL_SYS_APLL_STATUS, status,
@@ -380,7 +346,7 @@ static int wait_for_sys_apll_dpll_lock(struct idtcm *idtcm)
                } else if (dpll == DPLL_STATE_FREERUN ||
                           dpll == DPLL_STATE_HOLDOVER ||
                           dpll == DPLL_STATE_OPEN_LOOP) {
-                       dev_warn(&idtcm->client->dev,
+                       dev_warn(idtcm->dev,
                                "No wait state: DPLL_SYS_STATE %d", dpll);
                        return -EPERM;
                }
@@ -388,7 +354,7 @@ static int wait_for_sys_apll_dpll_lock(struct idtcm *idtcm)
                msleep(LOCK_POLL_INTERVAL_MS);
        } while (time_is_after_jiffies(timeout));
 
-       dev_warn(&idtcm->client->dev,
+       dev_warn(idtcm->dev,
                 "%d ms lock timeout: SYS APLL Loss Lock %d  SYS DPLL state %d",
                 LOCK_TIMEOUT_MS, apll, dpll);
 
@@ -398,39 +364,27 @@ static int wait_for_sys_apll_dpll_lock(struct idtcm *idtcm)
 static void wait_for_chip_ready(struct idtcm *idtcm)
 {
        if (wait_for_boot_status_ready(idtcm))
-               dev_warn(&idtcm->client->dev, "BOOT_STATUS != 0xA0");
+               dev_warn(idtcm->dev, "BOOT_STATUS != 0xA0");
 
        if (wait_for_sys_apll_dpll_lock(idtcm))
-               dev_warn(&idtcm->client->dev,
+               dev_warn(idtcm->dev,
                         "Continuing while SYS APLL/DPLL is not locked");
 }
 
 static int _idtcm_gettime(struct idtcm_channel *channel,
-                         struct timespec64 *ts)
+                         struct timespec64 *ts, u8 timeout)
 {
        struct idtcm *idtcm = channel->idtcm;
        u16 tod_read_cmd = IDTCM_FW_REG(idtcm->fw_ver, V520, TOD_READ_PRIMARY_CMD);
        u8 buf[TOD_BYTE_COUNT];
-       u8 timeout = 10;
        u8 trigger;
        int err;
 
-       err = idtcm_read(idtcm, channel->tod_read_primary,
-                        tod_read_cmd, &trigger, sizeof(trigger));
-       if (err)
-               return err;
-
-       trigger &= ~(TOD_READ_TRIGGER_MASK << TOD_READ_TRIGGER_SHIFT);
-       trigger |= (1 << TOD_READ_TRIGGER_SHIFT);
-       trigger &= ~TOD_READ_TRIGGER_MODE; /* single shot */
-
-       err = idtcm_write(idtcm, channel->tod_read_primary,
-                         tod_read_cmd, &trigger, sizeof(trigger));
-       if (err)
-               return err;
-
        /* wait trigger to be 0 */
-       while (trigger & TOD_READ_TRIGGER_MASK) {
+       do {
+               if (timeout-- == 0)
+                       return -EIO;
+
                if (idtcm->calculate_overhead_flag)
                        idtcm->start_time = ktime_get_raw();
 
@@ -439,10 +393,7 @@ static int _idtcm_gettime(struct idtcm_channel *channel,
                                 sizeof(trigger));
                if (err)
                        return err;
-
-               if (--timeout == 0)
-                       return -EIO;
-       }
+       } while (trigger & TOD_READ_TRIGGER_MASK);
 
        err = idtcm_read(idtcm, channel->tod_read_primary,
                         TOD_READ_PRIMARY, buf, sizeof(buf));
@@ -454,6 +405,79 @@ static int _idtcm_gettime(struct idtcm_channel *channel,
        return err;
 }
 
+static int idtcm_extts_check_channel(struct idtcm *idtcm, u8 todn)
+{
+       struct idtcm_channel *ptp_channel, *extts_channel;
+       struct ptp_clock_event event;
+       struct timespec64 ts;
+       u32 dco_delay = 0;
+       int err;
+
+       extts_channel = &idtcm->channel[todn];
+       ptp_channel = idtcm->event_channel[todn];
+       if (extts_channel == ptp_channel)
+               dco_delay = ptp_channel->dco_delay;
+
+       err = _idtcm_gettime(extts_channel, &ts, 1);
+       if (err == 0) {
+               event.type = PTP_CLOCK_EXTTS;
+               event.index = todn;
+               event.timestamp = timespec64_to_ns(&ts) - dco_delay;
+               ptp_clock_event(ptp_channel->ptp_clock, &event);
+       }
+       return err;
+}
+
+static u8 idtcm_enable_extts_mask(struct idtcm_channel *channel,
+                                   u8 extts_mask, bool enable)
+{
+       struct idtcm *idtcm = channel->idtcm;
+       int i, err;
+
+       for (i = 0; i < MAX_TOD; i++) {
+               u8 mask = 1 << i;
+               u8 refn = idtcm->channel[i].refn;
+
+               if (extts_mask & mask) {
+                       /* check extts before disabling it */
+                       if (enable == false) {
+                               err = idtcm_extts_check_channel(idtcm, i);
+                               /* trigger happened so we won't re-enable it */
+                               if (err == 0)
+                                       extts_mask &= ~mask;
+                       }
+                       (void)idtcm_enable_extts(channel, i, refn, enable);
+               }
+       }
+
+       return extts_mask;
+}
+
+static int _idtcm_gettime_immediate(struct idtcm_channel *channel,
+                                   struct timespec64 *ts)
+{
+       struct idtcm *idtcm = channel->idtcm;
+       u8 extts_mask = 0;
+       int err;
+
+       /* Disable extts */
+       if (idtcm->extts_mask) {
+               extts_mask = idtcm_enable_extts_mask(channel, idtcm->extts_mask,
+                                                    false);
+       }
+
+       err = _idtcm_set_scsr_read_trig(channel,
+                                       SCSR_TOD_READ_TRIG_SEL_IMMEDIATE, 0);
+       if (err == 0)
+               err = _idtcm_gettime(channel, ts, 10);
+
+       /* Re-enable extts */
+       if (extts_mask)
+               idtcm_enable_extts_mask(channel, extts_mask, true);
+
+       return err;
+}
+
 static int _sync_pll_output(struct idtcm *idtcm,
                            u8 pll,
                            u8 sync_src,
@@ -777,7 +801,7 @@ static int _idtcm_set_dpll_scsr_tod(struct idtcm_channel *channel,
                        break;
 
                if (++count > 20) {
-                       dev_err(&idtcm->client->dev,
+                       dev_err(idtcm->dev,
                                "Timed out waiting for the write counter");
                        return -EIO;
                }
@@ -842,7 +866,7 @@ static int _idtcm_settime_deprecated(struct idtcm_channel *channel,
 
        err = _idtcm_set_dpll_hw_tod(channel, ts, HW_TOD_WR_TRIG_SEL_MSB);
        if (err) {
-               dev_err(&idtcm->client->dev,
+               dev_err(idtcm->dev,
                        "%s: Set HW ToD failed", __func__);
                return err;
        }
@@ -1001,7 +1025,7 @@ static int _idtcm_adjtime_deprecated(struct idtcm_channel *channel, s64 delta)
                if (err)
                        return err;
 
-               err = _idtcm_gettime(channel, &ts);
+               err = _idtcm_gettime_immediate(channel, &ts);
                if (err)
                        return err;
 
@@ -1035,14 +1059,14 @@ static int idtcm_state_machine_reset(struct idtcm *idtcm)
                        read_boot_status(idtcm, &status);
 
                        if (status == 0xA0) {
-                               dev_dbg(&idtcm->client->dev,
+                               dev_dbg(idtcm->dev,
                                        "SM_RESET completed in %d ms", i * 100);
                                break;
                        }
                }
 
                if (!status)
-                       dev_err(&idtcm->client->dev,
+                       dev_err(idtcm->dev,
                                "Timed out waiting for CM_RESET to complete");
        }
 
@@ -1139,12 +1163,12 @@ static int set_pll_output_mask(struct idtcm *idtcm, u16 addr, u8 val)
 static int set_tod_ptp_pll(struct idtcm *idtcm, u8 index, u8 pll)
 {
        if (index >= MAX_TOD) {
-               dev_err(&idtcm->client->dev, "ToD%d not supported", index);
+               dev_err(idtcm->dev, "ToD%d not supported", index);
                return -EINVAL;
        }
 
        if (pll >= MAX_PLL) {
-               dev_err(&idtcm->client->dev, "Pll%d not supported", pll);
+               dev_err(idtcm->dev, "Pll%d not supported", pll);
                return -EINVAL;
        }
 
@@ -1162,7 +1186,7 @@ static int check_and_set_masks(struct idtcm *idtcm,
        switch (regaddr) {
        case TOD_MASK_ADDR:
                if ((val & 0xf0) || !(val & 0x0f)) {
-                       dev_err(&idtcm->client->dev, "Invalid TOD mask 0x%02x", val);
+                       dev_err(idtcm->dev, "Invalid TOD mask 0x%02x", val);
                        err = -EINVAL;
                } else {
                        idtcm->tod_mask = val;
@@ -1193,13 +1217,13 @@ static void display_pll_and_masks(struct idtcm *idtcm)
        u8 i;
        u8 mask;
 
-       dev_dbg(&idtcm->client->dev, "tod_mask = 0x%02x", idtcm->tod_mask);
+       dev_dbg(idtcm->dev, "tod_mask = 0x%02x", idtcm->tod_mask);
 
        for (i = 0; i < MAX_TOD; i++) {
                mask = 1 << i;
 
                if (mask & idtcm->tod_mask)
-                       dev_dbg(&idtcm->client->dev,
+                       dev_dbg(idtcm->dev,
                                "TOD%d pll = %d    output_mask = 0x%04x",
                                i, idtcm->channel[i].pll,
                                idtcm->channel[i].output_mask);
@@ -1222,16 +1246,16 @@ static int idtcm_load_firmware(struct idtcm *idtcm,
        if (firmware) /* module parameter */
                snprintf(fname, sizeof(fname), "%s", firmware);
 
-       dev_info(&idtcm->client->dev, "firmware '%s'", fname);
+       dev_info(idtcm->dev, "requesting firmware '%s'", fname);
 
        err = request_firmware(&fw, fname, dev);
        if (err) {
-               dev_err(&idtcm->client->dev,
+               dev_err(idtcm->dev,
                        "Failed at line %d in %s!", __LINE__, __func__);
                return err;
        }
 
-       dev_dbg(&idtcm->client->dev, "firmware size %zu bytes", fw->size);
+       dev_dbg(idtcm->dev, "firmware size %zu bytes", fw->size);
 
        rec = (struct idtcm_fwrc *) fw->data;
 
@@ -1240,7 +1264,7 @@ static int idtcm_load_firmware(struct idtcm *idtcm,
 
        for (len = fw->size; len > 0; len -= sizeof(*rec)) {
                if (rec->reserved) {
-                       dev_err(&idtcm->client->dev,
+                       dev_err(idtcm->dev,
                                "bad firmware, reserved field non-zero");
                        err = -EINVAL;
                } else {
@@ -1291,7 +1315,7 @@ static int idtcm_output_enable(struct idtcm_channel *channel,
        base = get_output_base_addr(idtcm->fw_ver, outn);
 
        if (!(base > 0)) {
-               dev_err(&idtcm->client->dev,
+               dev_err(idtcm->dev,
                        "%s - Unsupported out%d", __func__, outn);
                return base;
        }
@@ -1333,8 +1357,8 @@ static int idtcm_output_mask_enable(struct idtcm_channel *channel,
 }
 
 static int idtcm_perout_enable(struct idtcm_channel *channel,
-                              bool enable,
-                              struct ptp_perout_request *perout)
+                              struct ptp_perout_request *perout,
+                              bool enable)
 {
        struct idtcm *idtcm = channel->idtcm;
        unsigned int flags = perout->flags;
@@ -1347,7 +1371,7 @@ static int idtcm_perout_enable(struct idtcm_channel *channel,
                err = idtcm_output_enable(channel, enable, perout->index);
 
        if (err) {
-               dev_err(&idtcm->client->dev, "Unable to set output enable");
+               dev_err(idtcm->dev, "Unable to set output enable");
                return err;
        }
 
@@ -1448,7 +1472,7 @@ static int configure_dpll_mode_write_frequency(struct idtcm_channel *channel)
        err = idtcm_set_pll_mode(channel, PLL_MODE_WRITE_FREQUENCY);
 
        if (err)
-               dev_err(&idtcm->client->dev, "Failed to set pll mode to write frequency");
+               dev_err(idtcm->dev, "Failed to set pll mode to write frequency");
        else
                channel->mode = PTP_PLL_MODE_WRITE_FREQUENCY;
 
@@ -1463,7 +1487,7 @@ static int configure_dpll_mode_write_phase(struct idtcm_channel *channel)
        err = idtcm_set_pll_mode(channel, PLL_MODE_WRITE_PHASE);
 
        if (err)
-               dev_err(&idtcm->client->dev, "Failed to set pll mode to write phase");
+               dev_err(idtcm->dev, "Failed to set pll mode to write phase");
        else
                channel->mode = PTP_PLL_MODE_WRITE_PHASE;
 
@@ -1478,7 +1502,7 @@ static int configure_manual_reference_write_frequency(struct idtcm_channel *chan
        err = idtcm_set_manual_reference(channel, MANU_REF_WRITE_FREQUENCY);
 
        if (err)
-               dev_err(&idtcm->client->dev, "Failed to set manual reference to write frequency");
+               dev_err(idtcm->dev, "Failed to set manual reference to write frequency");
        else
                channel->mode = PTP_PLL_MODE_WRITE_FREQUENCY;
 
@@ -1493,7 +1517,7 @@ static int configure_manual_reference_write_phase(struct idtcm_channel *channel)
        err = idtcm_set_manual_reference(channel, MANU_REF_WRITE_PHASE);
 
        if (err)
-               dev_err(&idtcm->client->dev, "Failed to set manual reference to write phase");
+               dev_err(idtcm->dev, "Failed to set manual reference to write phase");
        else
                channel->mode = PTP_PLL_MODE_WRITE_PHASE;
 
@@ -1518,11 +1542,11 @@ static long idtcm_work_handler(struct ptp_clock_info *ptp)
        struct idtcm_channel *channel = container_of(ptp, struct idtcm_channel, caps);
        struct idtcm *idtcm = channel->idtcm;
 
-       mutex_lock(&idtcm->reg_lock);
+       mutex_lock(idtcm->lock);
 
        (void)idtcm_stop_phase_pull_in(channel);
 
-       mutex_unlock(&idtcm->reg_lock);
+       mutex_unlock(idtcm->lock);
 
        /* Return a negative value here to not reschedule */
        return -1;
@@ -1533,8 +1557,8 @@ static s32 phase_pull_in_scaled_ppm(s32 current_ppm, s32 phase_pull_in_ppb)
        /* ppb = scaled_ppm * 125 / 2^13 */
        /* scaled_ppm = ppb * 2^13 / 125 */
 
-       s64 max_scaled_ppm = (PHASE_PULL_IN_MAX_PPB << 13) / 125;
-       s64 scaled_ppm = (phase_pull_in_ppb << 13) / 125;
+       s64 max_scaled_ppm = div_s64((s64)PHASE_PULL_IN_MAX_PPB << 13, 125);
+       s64 scaled_ppm = div_s64((s64)phase_pull_in_ppb << 13, 125);
 
        current_ppm += scaled_ppm;
 
@@ -1607,7 +1631,7 @@ static int initialize_operating_mode_with_manual_reference(struct idtcm_channel
                channel->mode = PTP_PLL_MODE_WRITE_FREQUENCY;
                break;
        default:
-               dev_warn(&idtcm->client->dev,
+               dev_warn(idtcm->dev,
                         "Unsupported MANUAL_REFERENCE: 0x%02x", ref);
        }
 
@@ -1633,7 +1657,7 @@ static int initialize_operating_mode_with_pll_mode(struct idtcm_channel *channel
                channel->mode = PTP_PLL_MODE_WRITE_FREQUENCY;
                break;
        default:
-               dev_err(&idtcm->client->dev,
+               dev_err(idtcm->dev,
                        "Unsupported PLL_MODE: 0x%02x", mode);
                err = -EINVAL;
        }
@@ -1652,14 +1676,14 @@ static int initialize_dco_operating_mode(struct idtcm_channel *channel)
 
        err = idtcm_get_pll_mode(channel, &mode);
        if (err) {
-               dev_err(&idtcm->client->dev, "Unable to read pll mode!");
+               dev_err(idtcm->dev, "Unable to read pll mode!");
                return err;
        }
 
        if (mode == PLL_MODE_PLL) {
                err = idtcm_get_manual_reference(channel, &ref);
                if (err) {
-                       dev_err(&idtcm->client->dev, "Unable to read manual reference!");
+                       dev_err(idtcm->dev, "Unable to read manual reference!");
                        return err;
                }
                err = initialize_operating_mode_with_manual_reference(channel, ref);
@@ -1775,15 +1799,14 @@ static int idtcm_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
        struct idtcm *idtcm = channel->idtcm;
        int err;
 
-       mutex_lock(&idtcm->reg_lock);
+       mutex_lock(idtcm->lock);
+       err = _idtcm_gettime_immediate(channel, ts);
+       mutex_unlock(idtcm->lock);
 
-       err = _idtcm_gettime(channel, ts);
        if (err)
-               dev_err(&idtcm->client->dev, "Failed at line %d in %s!",
+               dev_err(idtcm->dev, "Failed at line %d in %s!",
                        __LINE__, __func__);
 
-       mutex_unlock(&idtcm->reg_lock);
-
        return err;
 }
 
@@ -1794,15 +1817,14 @@ static int idtcm_settime_deprecated(struct ptp_clock_info *ptp,
        struct idtcm *idtcm = channel->idtcm;
        int err;
 
-       mutex_lock(&idtcm->reg_lock);
-
+       mutex_lock(idtcm->lock);
        err = _idtcm_settime_deprecated(channel, ts);
+       mutex_unlock(idtcm->lock);
+
        if (err)
-               dev_err(&idtcm->client->dev,
+               dev_err(idtcm->dev,
                        "Failed at line %d in %s!", __LINE__, __func__);
 
-       mutex_unlock(&idtcm->reg_lock);
-
        return err;
 }
 
@@ -1813,15 +1835,14 @@ static int idtcm_settime(struct ptp_clock_info *ptp,
        struct idtcm *idtcm = channel->idtcm;
        int err;
 
-       mutex_lock(&idtcm->reg_lock);
-
+       mutex_lock(idtcm->lock);
        err = _idtcm_settime(channel, ts, SCSR_TOD_WR_TYPE_SEL_ABSOLUTE);
+       mutex_unlock(idtcm->lock);
+
        if (err)
-               dev_err(&idtcm->client->dev,
+               dev_err(idtcm->dev,
                        "Failed at line %d in %s!", __LINE__, __func__);
 
-       mutex_unlock(&idtcm->reg_lock);
-
        return err;
 }
 
@@ -1831,15 +1852,14 @@ static int idtcm_adjtime_deprecated(struct ptp_clock_info *ptp, s64 delta)
        struct idtcm *idtcm = channel->idtcm;
        int err;
 
-       mutex_lock(&idtcm->reg_lock);
-
+       mutex_lock(idtcm->lock);
        err = _idtcm_adjtime_deprecated(channel, delta);
+       mutex_unlock(idtcm->lock);
+
        if (err)
-               dev_err(&idtcm->client->dev,
+               dev_err(idtcm->dev,
                        "Failed at line %d in %s!", __LINE__, __func__);
 
-       mutex_unlock(&idtcm->reg_lock);
-
        return err;
 }
 
@@ -1854,13 +1874,10 @@ static int idtcm_adjtime(struct ptp_clock_info *ptp, s64 delta)
        if (channel->phase_pull_in == true)
                return 0;
 
-       mutex_lock(&idtcm->reg_lock);
+       mutex_lock(idtcm->lock);
 
        if (abs(delta) < PHASE_PULL_IN_THRESHOLD_NS) {
                err = channel->do_phase_pull_in(channel, delta, 0);
-               if (err)
-                       dev_err(&idtcm->client->dev,
-                               "Failed at line %d in %s!", __LINE__, __func__);
        } else {
                if (delta >= 0) {
                        ts = ns_to_timespec64(delta);
@@ -1870,11 +1887,13 @@ static int idtcm_adjtime(struct ptp_clock_info *ptp, s64 delta)
                        type = SCSR_TOD_WR_TYPE_SEL_DELTA_MINUS;
                }
                err = _idtcm_settime(channel, &ts, type);
-               if (err)
-                       dev_err(&idtcm->client->dev,
-                               "Failed at line %d in %s!", __LINE__, __func__);
        }
-       mutex_unlock(&idtcm->reg_lock);
+
+       mutex_unlock(idtcm->lock);
+
+       if (err)
+               dev_err(idtcm->dev,
+                       "Failed at line %d in %s!", __LINE__, __func__);
 
        return err;
 }
@@ -1885,15 +1904,14 @@ static int idtcm_adjphase(struct ptp_clock_info *ptp, s32 delta)
        struct idtcm *idtcm = channel->idtcm;
        int err;
 
-       mutex_lock(&idtcm->reg_lock);
-
+       mutex_lock(idtcm->lock);
        err = _idtcm_adjphase(channel, delta);
+       mutex_unlock(idtcm->lock);
+
        if (err)
-               dev_err(&idtcm->client->dev,
+               dev_err(idtcm->dev,
                        "Failed at line %d in %s!", __LINE__, __func__);
 
-       mutex_unlock(&idtcm->reg_lock);
-
        return err;
 }
 
@@ -1909,13 +1927,14 @@ static int idtcm_adjfine(struct ptp_clock_info *ptp,  long scaled_ppm)
        if (scaled_ppm == channel->current_freq_scaled_ppm)
                return 0;
 
-       mutex_lock(&idtcm->reg_lock);
-
+       mutex_lock(idtcm->lock);
        err = _idtcm_adjfine(channel, scaled_ppm);
+       mutex_unlock(idtcm->lock);
 
-       mutex_unlock(&idtcm->reg_lock);
-
-       if (!err)
+       if (err)
+               dev_err(idtcm->dev,
+                       "Failed at line %d in %s!", __LINE__, __func__);
+       else
                channel->current_freq_scaled_ppm = scaled_ppm;
 
        return err;
@@ -1924,35 +1943,38 @@ static int idtcm_adjfine(struct ptp_clock_info *ptp,  long scaled_ppm)
 static int idtcm_enable(struct ptp_clock_info *ptp,
                        struct ptp_clock_request *rq, int on)
 {
-       int err;
        struct idtcm_channel *channel = container_of(ptp, struct idtcm_channel, caps);
+       struct idtcm *idtcm = channel->idtcm;
+       int err = -EOPNOTSUPP;
+
+       mutex_lock(idtcm->lock);
 
        switch (rq->type) {
        case PTP_CLK_REQ_PEROUT:
-               if (!on) {
-                       err = idtcm_perout_enable(channel, false, &rq->perout);
-                       if (err)
-                               dev_err(&channel->idtcm->client->dev,
-                                       "Failed at line %d in %s!",
-                                       __LINE__, __func__);
-                       return err;
-               }
-
+               if (!on)
+                       err = idtcm_perout_enable(channel, &rq->perout, false);
                /* Only accept a 1-PPS aligned to the second. */
-               if (rq->perout.start.nsec || rq->perout.period.sec != 1 ||
-                   rq->perout.period.nsec)
-                       return -ERANGE;
-
-               err = idtcm_perout_enable(channel, true, &rq->perout);
-               if (err)
-                       dev_err(&channel->idtcm->client->dev,
-                               "Failed at line %d in %s!", __LINE__, __func__);
-               return err;
+               else if (rq->perout.start.nsec || rq->perout.period.sec != 1 ||
+                        rq->perout.period.nsec)
+                       err = -ERANGE;
+               else
+                       err = idtcm_perout_enable(channel, &rq->perout, true);
+               break;
+       case PTP_CLK_REQ_EXTTS:
+               err = idtcm_enable_extts(channel, rq->extts.index,
+                                        rq->extts.rsv[0], on);
+               break;
        default:
                break;
        }
 
-       return -EOPNOTSUPP;
+       mutex_unlock(idtcm->lock);
+
+       if (err)
+               dev_err(channel->idtcm->dev,
+                       "Failed in %s with err %d!", __func__, err);
+
+       return err;
 }
 
 static int idtcm_enable_tod(struct idtcm_channel *channel)
@@ -2013,7 +2035,7 @@ static void idtcm_set_version_info(struct idtcm *idtcm)
 
        idtcm->fw_ver = idtcm_fw_version(idtcm->version);
 
-       dev_info(&idtcm->client->dev,
+       dev_info(idtcm->dev,
                 "%d.%d.%d, Id: 0x%04x  HW Rev: %d  OTP Config Select: %d",
                 major, minor, hotfix,
                 product_id, hw_rev_id, config_select);
@@ -2023,6 +2045,7 @@ static const struct ptp_clock_info idtcm_caps = {
        .owner          = THIS_MODULE,
        .max_adj        = 244000,
        .n_per_out      = 12,
+       .n_ext_ts       = MAX_TOD,
        .adjphase       = &idtcm_adjphase,
        .adjfine        = &idtcm_adjfine,
        .adjtime        = &idtcm_adjtime,
@@ -2036,6 +2059,7 @@ static const struct ptp_clock_info idtcm_caps_deprecated = {
        .owner          = THIS_MODULE,
        .max_adj        = 244000,
        .n_per_out      = 12,
+       .n_ext_ts       = MAX_TOD,
        .adjphase       = &idtcm_adjphase,
        .adjfine        = &idtcm_adjfine,
        .adjtime        = &idtcm_adjtime_deprecated,
@@ -2122,24 +2146,46 @@ static int configure_channel_pll(struct idtcm_channel *channel)
        return err;
 }
 
-static int idtcm_enable_channel(struct idtcm *idtcm, u32 index)
+/*
+ * Compensate for the PTP DCO input-to-output delay.
+ * This delay is 18 FOD cycles.
+ */
+static u32 idtcm_get_dco_delay(struct idtcm_channel *channel)
 {
-       enum fw_version fw_ver = idtcm->fw_ver;
-       struct idtcm_channel *channel;
+       struct idtcm *idtcm = channel->idtcm;
+       u8 mbuf[8] = {0};
+       u8 nbuf[2] = {0};
+       u32 fodFreq;
        int err;
+       u64 m;
+       u16 n;
 
-       if (!(index < MAX_TOD))
-               return -EINVAL;
+       err = idtcm_read(idtcm, channel->dpll_ctrl_n,
+                        DPLL_CTRL_DPLL_FOD_FREQ, mbuf, 6);
+       if (err)
+               return 0;
 
-       channel = &idtcm->channel[index];
+       err = idtcm_read(idtcm, channel->dpll_ctrl_n,
+                        DPLL_CTRL_DPLL_FOD_FREQ + 6, nbuf, 2);
+       if (err)
+               return 0;
 
-       channel->idtcm = idtcm;
-       channel->current_freq_scaled_ppm = 0;
+       m = get_unaligned_le64(mbuf);
+       n = get_unaligned_le16(nbuf);
 
-       /* Set pll addresses */
-       err = configure_channel_pll(channel);
-       if (err)
-               return err;
+       if (n == 0)
+               n = 1;
+
+       fodFreq = (u32)div_u64(m, n);
+       if (fodFreq >= 500000000)
+               return 18 * (u32)div_u64(NSEC_PER_SEC, fodFreq);
+
+       return 0;
+}
+
+static int configure_channel_tod(struct idtcm_channel *channel, u32 index)
+{
+       enum fw_version fw_ver = channel->idtcm->fw_ver;
 
        /* Set tod addresses */
        switch (index) {
@@ -2171,6 +2217,32 @@ static int idtcm_enable_channel(struct idtcm *idtcm, u32 index)
                return -EINVAL;
        }
 
+       return 0;
+}
+
+static int idtcm_enable_channel(struct idtcm *idtcm, u32 index)
+{
+       struct idtcm_channel *channel;
+       int err;
+
+       if (!(index < MAX_TOD))
+               return -EINVAL;
+
+       channel = &idtcm->channel[index];
+
+       channel->idtcm = idtcm;
+       channel->current_freq_scaled_ppm = 0;
+
+       /* Set pll addresses */
+       err = configure_channel_pll(channel);
+       if (err)
+               return err;
+
+       /* Set tod addresses */
+       err = configure_channel_tod(channel, index);
+       if (err)
+               return err;
+
        if (idtcm->fw_ver < V487)
                channel->caps = idtcm_caps_deprecated;
        else
@@ -2185,11 +2257,13 @@ static int idtcm_enable_channel(struct idtcm *idtcm, u32 index)
 
        err = idtcm_enable_tod(channel);
        if (err) {
-               dev_err(&idtcm->client->dev,
+               dev_err(idtcm->dev,
                        "Failed at line %d in %s!", __LINE__, __func__);
                return err;
        }
 
+       channel->dco_delay = idtcm_get_dco_delay(channel);
+
        channel->ptp_clock = ptp_clock_register(&channel->caps, NULL);
 
        if (IS_ERR(channel->ptp_clock)) {
@@ -2201,12 +2275,59 @@ static int idtcm_enable_channel(struct idtcm *idtcm, u32 index)
        if (!channel->ptp_clock)
                return -ENOTSUPP;
 
-       dev_info(&idtcm->client->dev, "PLL%d registered as ptp%d",
+       dev_info(idtcm->dev, "PLL%d registered as ptp%d",
                 index, channel->ptp_clock->index);
 
        return 0;
 }
 
+static int idtcm_enable_extts_channel(struct idtcm *idtcm, u32 index)
+{
+       struct idtcm_channel *channel;
+       int err;
+
+       if (!(index < MAX_TOD))
+               return -EINVAL;
+
+       channel = &idtcm->channel[index];
+       channel->idtcm = idtcm;
+
+       /* Set tod addresses */
+       err = configure_channel_tod(channel, index);
+       if (err)
+               return err;
+
+       channel->idtcm = idtcm;
+
+       return 0;
+}
+
+static void idtcm_extts_check(struct work_struct *work)
+{
+       struct idtcm *idtcm = container_of(work, struct idtcm, extts_work.work);
+       int err, i;
+
+       if (idtcm->extts_mask == 0)
+               return;
+
+       mutex_lock(idtcm->lock);
+       for (i = 0; i < MAX_TOD; i++) {
+               u8 mask = 1 << i;
+
+               if (idtcm->extts_mask & mask) {
+                       err = idtcm_extts_check_channel(idtcm, i);
+                       /* trigger clears itself, so clear the mask */
+                       if (err == 0)
+                               idtcm->extts_mask &= ~mask;
+               }
+       }
+
+       if (idtcm->extts_mask)
+               schedule_delayed_work(&idtcm->extts_work,
+                                     msecs_to_jiffies(EXTTS_PERIOD_MS));
+       mutex_unlock(idtcm->lock);
+}
+
 static void ptp_clock_unregister_all(struct idtcm *idtcm)
 {
        u8 i;
@@ -2222,6 +2343,7 @@ static void ptp_clock_unregister_all(struct idtcm *idtcm)
 static void set_default_masks(struct idtcm *idtcm)
 {
        idtcm->tod_mask = DEFAULT_TOD_MASK;
+       idtcm->extts_mask = 0;
 
        idtcm->channel[0].pll = DEFAULT_TOD0_PTP_PLL;
        idtcm->channel[1].pll = DEFAULT_TOD1_PTP_PLL;
@@ -2234,158 +2356,86 @@ static void set_default_masks(struct idtcm *idtcm)
        idtcm->channel[3].output_mask = DEFAULT_OUTPUT_MASK_PLL3;
 }
 
-static int idtcm_probe(struct i2c_client *client,
-                      const struct i2c_device_id *id)
+static int idtcm_probe(struct platform_device *pdev)
 {
+       struct rsmu_ddata *ddata = dev_get_drvdata(pdev->dev.parent);
        struct idtcm *idtcm;
        int err;
        u8 i;
 
-       /* Unused for now */
-       (void)id;
-
-       idtcm = devm_kzalloc(&client->dev, sizeof(struct idtcm), GFP_KERNEL);
+       idtcm = devm_kzalloc(&pdev->dev, sizeof(struct idtcm), GFP_KERNEL);
 
        if (!idtcm)
                return -ENOMEM;
 
-       idtcm->client = client;
-       idtcm->page_offset = 0xff;
+       idtcm->dev = &pdev->dev;
+       idtcm->mfd = pdev->dev.parent;
+       idtcm->lock = &ddata->lock;
+       idtcm->regmap = ddata->regmap;
        idtcm->calculate_overhead_flag = 0;
 
+       INIT_DELAYED_WORK(&idtcm->extts_work, idtcm_extts_check);
+
        set_default_masks(idtcm);
 
-       mutex_init(&idtcm->reg_lock);
-       mutex_lock(&idtcm->reg_lock);
+       mutex_lock(idtcm->lock);
 
        idtcm_set_version_info(idtcm);
 
-       err = idtcm_load_firmware(idtcm, &client->dev);
+       err = idtcm_load_firmware(idtcm, &pdev->dev);
+
        if (err)
-               dev_warn(&idtcm->client->dev, "loading firmware failed with %d", err);
+               dev_warn(idtcm->dev, "loading firmware failed with %d", err);
 
        wait_for_chip_ready(idtcm);
 
        if (idtcm->tod_mask) {
                for (i = 0; i < MAX_TOD; i++) {
-                       if (idtcm->tod_mask & (1 << i)) {
+                       if (idtcm->tod_mask & (1 << i))
                                err = idtcm_enable_channel(idtcm, i);
-                               if (err) {
-                                       dev_err(&idtcm->client->dev,
-                                               "idtcm_enable_channel %d failed!", i);
-                                       break;
-                               }
+                       else
+                               err = idtcm_enable_extts_channel(idtcm, i);
+                       if (err) {
+                               dev_err(idtcm->dev,
+                                       "idtcm_enable_channel %d failed!", i);
+                               break;
                        }
                }
        } else {
-               dev_err(&idtcm->client->dev,
+               dev_err(idtcm->dev,
                        "no PLLs flagged as PHCs, nothing to do");
                err = -ENODEV;
        }
 
-       mutex_unlock(&idtcm->reg_lock);
+       mutex_unlock(idtcm->lock);
 
        if (err) {
                ptp_clock_unregister_all(idtcm);
                return err;
        }
 
-       i2c_set_clientdata(client, idtcm);
+       platform_set_drvdata(pdev, idtcm);
 
        return 0;
 }
 
-static int idtcm_remove(struct i2c_client *client)
+static int idtcm_remove(struct platform_device *pdev)
 {
-       struct idtcm *idtcm = i2c_get_clientdata(client);
+       struct idtcm *idtcm = platform_get_drvdata(pdev);
 
        ptp_clock_unregister_all(idtcm);
 
-       mutex_destroy(&idtcm->reg_lock);
+       cancel_delayed_work_sync(&idtcm->extts_work);
 
        return 0;
 }
 
-#ifdef CONFIG_OF
-static const struct of_device_id idtcm_dt_id[] = {
-       { .compatible = "idt,8a34000" },
-       { .compatible = "idt,8a34001" },
-       { .compatible = "idt,8a34002" },
-       { .compatible = "idt,8a34003" },
-       { .compatible = "idt,8a34004" },
-       { .compatible = "idt,8a34005" },
-       { .compatible = "idt,8a34006" },
-       { .compatible = "idt,8a34007" },
-       { .compatible = "idt,8a34008" },
-       { .compatible = "idt,8a34009" },
-       { .compatible = "idt,8a34010" },
-       { .compatible = "idt,8a34011" },
-       { .compatible = "idt,8a34012" },
-       { .compatible = "idt,8a34013" },
-       { .compatible = "idt,8a34014" },
-       { .compatible = "idt,8a34015" },
-       { .compatible = "idt,8a34016" },
-       { .compatible = "idt,8a34017" },
-       { .compatible = "idt,8a34018" },
-       { .compatible = "idt,8a34019" },
-       { .compatible = "idt,8a34040" },
-       { .compatible = "idt,8a34041" },
-       { .compatible = "idt,8a34042" },
-       { .compatible = "idt,8a34043" },
-       { .compatible = "idt,8a34044" },
-       { .compatible = "idt,8a34045" },
-       { .compatible = "idt,8a34046" },
-       { .compatible = "idt,8a34047" },
-       { .compatible = "idt,8a34048" },
-       { .compatible = "idt,8a34049" },
-       {},
-};
-MODULE_DEVICE_TABLE(of, idtcm_dt_id);
-#endif
-
-static const struct i2c_device_id idtcm_i2c_id[] = {
-       { "8a34000" },
-       { "8a34001" },
-       { "8a34002" },
-       { "8a34003" },
-       { "8a34004" },
-       { "8a34005" },
-       { "8a34006" },
-       { "8a34007" },
-       { "8a34008" },
-       { "8a34009" },
-       { "8a34010" },
-       { "8a34011" },
-       { "8a34012" },
-       { "8a34013" },
-       { "8a34014" },
-       { "8a34015" },
-       { "8a34016" },
-       { "8a34017" },
-       { "8a34018" },
-       { "8a34019" },
-       { "8a34040" },
-       { "8a34041" },
-       { "8a34042" },
-       { "8a34043" },
-       { "8a34044" },
-       { "8a34045" },
-       { "8a34046" },
-       { "8a34047" },
-       { "8a34048" },
-       { "8a34049" },
-       {},
-};
-MODULE_DEVICE_TABLE(i2c, idtcm_i2c_id);
-
-static struct i2c_driver idtcm_driver = {
+static struct platform_driver idtcm_driver = {
        .driver = {
-               .of_match_table = of_match_ptr(idtcm_dt_id),
-               .name           = "idtcm",
+               .name = "8a3400x-phc",
        },
-       .probe          = idtcm_probe,
-       .remove         = idtcm_remove,
-       .id_table       = idtcm_i2c_id,
+       .probe = idtcm_probe,
+       .remove = idtcm_remove,
 };
 
-module_i2c_driver(idtcm_driver);
+module_platform_driver(idtcm_driver);
index 833e590..0f3059a 100644 (file)
@@ -9,8 +9,8 @@
 #define PTP_IDTCLOCKMATRIX_H
 
 #include <linux/ktime.h>
-
-#include "idt8a340_reg.h"
+#include <linux/mfd/idt8a340_reg.h>
+#include <linux/regmap.h>
 
 #define FW_FILENAME    "idtcm.bin"
 #define MAX_TOD                (4)
@@ -44,7 +44,6 @@
 #define DEFAULT_TOD2_PTP_PLL           (2)
 #define DEFAULT_TOD3_PTP_PLL           (3)
 
-#define POST_SM_RESET_DELAY_MS                 (3000)
 #define PHASE_PULL_IN_THRESHOLD_NS_DEPRECATED  (150000)
 #define PHASE_PULL_IN_THRESHOLD_NS             (15000)
 #define TOD_WRITE_OVERHEAD_COUNT_MAX           (2)
  * Return register address based on passed in firmware version
  */
 #define IDTCM_FW_REG(FW, VER, REG)     (((FW) < (VER)) ? (REG) : (REG##_##VER))
+enum fw_version {
+       V_DEFAULT = 0,
+       V487 = 1,
+       V520 = 2,
+};
 
 /* PTP PLL Mode */
 enum ptp_pll_mode {
@@ -74,94 +78,6 @@ enum ptp_pll_mode {
        PTP_PLL_MODE_MAX = PTP_PLL_MODE_UNSUPPORTED,
 };
 
-/* Values of DPLL_N.DPLL_MODE.PLL_MODE */
-enum pll_mode {
-       PLL_MODE_MIN = 0,
-       PLL_MODE_PLL = PLL_MODE_MIN,
-       PLL_MODE_WRITE_PHASE = 1,
-       PLL_MODE_WRITE_FREQUENCY = 2,
-       PLL_MODE_GPIO_INC_DEC = 3,
-       PLL_MODE_SYNTHESIS = 4,
-       PLL_MODE_PHASE_MEASUREMENT = 5,
-       PLL_MODE_DISABLED = 6,
-       PLL_MODE_MAX = PLL_MODE_DISABLED,
-};
-
-/* Values of DPLL_CTRL_n.DPLL_MANU_REF_CFG.MANUAL_REFERENCE */
-enum manual_reference {
-       MANU_REF_MIN = 0,
-       MANU_REF_CLK0 = MANU_REF_MIN,
-       MANU_REF_CLK1,
-       MANU_REF_CLK2,
-       MANU_REF_CLK3,
-       MANU_REF_CLK4,
-       MANU_REF_CLK5,
-       MANU_REF_CLK6,
-       MANU_REF_CLK7,
-       MANU_REF_CLK8,
-       MANU_REF_CLK9,
-       MANU_REF_CLK10,
-       MANU_REF_CLK11,
-       MANU_REF_CLK12,
-       MANU_REF_CLK13,
-       MANU_REF_CLK14,
-       MANU_REF_CLK15,
-       MANU_REF_WRITE_PHASE,
-       MANU_REF_WRITE_FREQUENCY,
-       MANU_REF_XO_DPLL,
-       MANU_REF_MAX = MANU_REF_XO_DPLL,
-};
-
-enum hw_tod_write_trig_sel {
-       HW_TOD_WR_TRIG_SEL_MIN = 0,
-       HW_TOD_WR_TRIG_SEL_MSB = HW_TOD_WR_TRIG_SEL_MIN,
-       HW_TOD_WR_TRIG_SEL_RESERVED = 1,
-       HW_TOD_WR_TRIG_SEL_TOD_PPS = 2,
-       HW_TOD_WR_TRIG_SEL_IRIGB_PPS = 3,
-       HW_TOD_WR_TRIG_SEL_PWM_PPS = 4,
-       HW_TOD_WR_TRIG_SEL_GPIO = 5,
-       HW_TOD_WR_TRIG_SEL_FOD_SYNC = 6,
-       WR_TRIG_SEL_MAX = HW_TOD_WR_TRIG_SEL_FOD_SYNC,
-};
-
-/* 4.8.7 only */
-enum scsr_tod_write_trig_sel {
-       SCSR_TOD_WR_TRIG_SEL_DISABLE = 0,
-       SCSR_TOD_WR_TRIG_SEL_IMMEDIATE = 1,
-       SCSR_TOD_WR_TRIG_SEL_REFCLK = 2,
-       SCSR_TOD_WR_TRIG_SEL_PWMPPS = 3,
-       SCSR_TOD_WR_TRIG_SEL_TODPPS = 4,
-       SCSR_TOD_WR_TRIG_SEL_SYNCFOD = 5,
-       SCSR_TOD_WR_TRIG_SEL_GPIO = 6,
-       SCSR_TOD_WR_TRIG_SEL_MAX = SCSR_TOD_WR_TRIG_SEL_GPIO,
-};
-
-/* 4.8.7 only */
-enum scsr_tod_write_type_sel {
-       SCSR_TOD_WR_TYPE_SEL_ABSOLUTE = 0,
-       SCSR_TOD_WR_TYPE_SEL_DELTA_PLUS = 1,
-       SCSR_TOD_WR_TYPE_SEL_DELTA_MINUS = 2,
-       SCSR_TOD_WR_TYPE_SEL_MAX = SCSR_TOD_WR_TYPE_SEL_DELTA_MINUS,
-};
-
-/* Values STATUS.DPLL_SYS_STATUS.DPLL_SYS_STATE */
-enum dpll_state {
-       DPLL_STATE_MIN = 0,
-       DPLL_STATE_FREERUN = DPLL_STATE_MIN,
-       DPLL_STATE_LOCKACQ = 1,
-       DPLL_STATE_LOCKREC = 2,
-       DPLL_STATE_LOCKED = 3,
-       DPLL_STATE_HOLDOVER = 4,
-       DPLL_STATE_OPEN_LOOP = 5,
-       DPLL_STATE_MAX = DPLL_STATE_OPEN_LOOP,
-};
-
-enum fw_version {
-       V_DEFAULT = 0,
-       V487 = 1,
-       V520 = 2,
-};
-
 struct idtcm;
 
 struct idtcm_channel {
@@ -185,25 +101,32 @@ struct idtcm_channel {
                                                    s32 offset_ns, u32 max_ffo_ppb);
        s32                     current_freq_scaled_ppm;
        bool                    phase_pull_in;
+       u32                     dco_delay;
+       /* last input trigger for extts */
+       u8                      refn;
        u8                      pll;
        u16                     output_mask;
 };
 
 struct idtcm {
        struct idtcm_channel    channel[MAX_TOD];
-       struct i2c_client       *client;
-       u8                      page_offset;
+       struct device           *dev;
        u8                      tod_mask;
        char                    version[16];
        enum fw_version         fw_ver;
-
+       /* Polls for external time stamps */
+       u8                      extts_mask;
+       struct delayed_work     extts_work;
+       /* Remember the ptp channel to report extts */
+       struct idtcm_channel    *event_channel[MAX_TOD];
+       /* Mutex to protect operations from being interrupted */
+       struct mutex            *lock;
+       struct device           *mfd;
+       struct regmap           *regmap;
        /* Overhead calculation for adjtime */
        u8                      calculate_overhead_flag;
        s64                     tod_write_overhead_ns;
        ktime_t                 start_time;
-
-       /* Protects I2C read/modify/write registers from concurrent access */
-       struct mutex            reg_lock;
 };
 
 struct idtcm_fwrc {
index 92d7632..a18c153 100644 (file)
 #define STATE_MODE_SHIFT                  (0)
 #define STATE_MODE_MASK                   (0x7)
 
+/* Bit definitions for the DPLL_MANU_REF_CFG register */
+#define MANUAL_REFERENCE_SHIFT            (0)
+#define MANUAL_REFERENCE_MASK             (0x1f)
+
 /* Bit definitions for the GPIO_CFG_GBL register */
 #define SUPPLY_MODE_SHIFT                 (0)
 #define SUPPLY_MODE_MASK                  (0x3)
 /* Values of DPLL_N.DPLL_MODE.PLL_MODE */
 enum pll_mode {
        PLL_MODE_MIN = 0,
-       PLL_MODE_NORMAL = PLL_MODE_MIN,
+       PLL_MODE_PLL = PLL_MODE_MIN,
        PLL_MODE_WRITE_PHASE = 1,
        PLL_MODE_WRITE_FREQUENCY = 2,
        PLL_MODE_GPIO_INC_DEC = 3,
@@ -664,6 +668,31 @@ enum pll_mode {
        PLL_MODE_MAX = PLL_MODE_DISABLED,
 };
 
+/* Values of DPLL_CTRL_n.DPLL_MANU_REF_CFG.MANUAL_REFERENCE */
+enum manual_reference {
+       MANU_REF_MIN = 0,
+       MANU_REF_CLK0 = MANU_REF_MIN,
+       MANU_REF_CLK1,
+       MANU_REF_CLK2,
+       MANU_REF_CLK3,
+       MANU_REF_CLK4,
+       MANU_REF_CLK5,
+       MANU_REF_CLK6,
+       MANU_REF_CLK7,
+       MANU_REF_CLK8,
+       MANU_REF_CLK9,
+       MANU_REF_CLK10,
+       MANU_REF_CLK11,
+       MANU_REF_CLK12,
+       MANU_REF_CLK13,
+       MANU_REF_CLK14,
+       MANU_REF_CLK15,
+       MANU_REF_WRITE_PHASE,
+       MANU_REF_WRITE_FREQUENCY,
+       MANU_REF_XO_DPLL,
+       MANU_REF_MAX = MANU_REF_XO_DPLL,
+};
+
 enum hw_tod_write_trig_sel {
        HW_TOD_WR_TRIG_SEL_MIN = 0,
        HW_TOD_WR_TRIG_SEL_MSB = HW_TOD_WR_TRIG_SEL_MIN,