diff mbox series

[v1] ptp: ocp: add Adva timecard support

Message ID 20231221153755.2690-1-maimon.sagi@gmail.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series [v1] ptp: ocp: add Adva timecard support | expand

Checks

Context Check Description
netdev/series_format warning Single patches do not need cover letters; Target tree name not specified in the subject
netdev/tree_selection success Guessed tree name to be net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 1115 this patch: 1115
netdev/cc_maintainers success CCed 4 of 4 maintainers
netdev/build_clang fail Errors and warnings before: 12 this patch: 14
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 1142 this patch: 1142
netdev/checkpatch warning CHECK: Please don't use multiple blank lines WARNING: line length of 104 exceeds 80 columns WARNING: line length of 85 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Sagi Maimon Dec. 21, 2023, 3:37 p.m. UTC
Adding support for the Adva timecard.
The card uses different drivers to provide access to the
firmware SPI flash (Altera based).
Other parts of the code are the same and could be reused.

Signed-off-by: Sagi Maimon <maimon.sagi@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 257 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 247 insertions(+), 10 deletions(-)

Comments

Vadim Fedorenko Dec. 21, 2023, 4:56 p.m. UTC | #1
On 21/12/2023 15:37, Sagi Maimon wrote:
> Adding support for the Adva timecard.
> The card uses different drivers to provide access to the
> firmware SPI flash (Altera based).
> Other parts of the code are the same and could be reused.
> 
> Signed-off-by: Sagi Maimon <maimon.sagi@gmail.com>
> ---
>   drivers/ptp/ptp_ocp.c | 257 ++++++++++++++++++++++++++++++++++++++++--
>   1 file changed, 247 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
> index 4021d3d325f9..73e91b8a2887 100644
> --- a/drivers/ptp/ptp_ocp.c
> +++ b/drivers/ptp/ptp_ocp.c
> @@ -34,6 +34,9 @@
>   #define PCI_VENDOR_ID_OROLIA			0x1ad7
>   #define PCI_DEVICE_ID_OROLIA_ARTCARD		0xa000
>   
> +#define PCI_VENDOR_ID_ADVA			0xad5a
> +#define PCI_DEVICE_ID_ADVA_TIMECARD		0x0400
> +
>   static struct class timecard_class = {
>   	.name		= "timecard",
>   };
> @@ -63,6 +66,13 @@ struct ocp_reg {
>   	u32	status_drift;
>   };
>   
> +struct servo_val {
> +	u32	servo_offset_p_val;
> +	u32	servo_offset_i_val;
> +	u32	servo_drift_p_val;
> +	u32	servo_drift_i_val;
> +};
> +

I don't really like naming here. Let's go with ptp_ocp prefix first.
Then it's more like configuration rather than actual values, so I would
say ptp_ocp_servo_conf is better here. And let's remove "_val" - no real
need for this suffix.

>   #define OCP_CTRL_ENABLE		BIT(0)
>   #define OCP_CTRL_ADJUST_TIME	BIT(1)
>   #define OCP_CTRL_ADJUST_OFFSET	BIT(2)
> @@ -401,6 +411,12 @@ static const struct ocp_attr_group fb_timecard_groups[];
>   
>   static const struct ocp_attr_group art_timecard_groups[];
>   
> +static int ptp_ocp_adva_board_init(struct ptp_ocp *bp, struct ocp_resource *r);
> +
> +static const struct ocp_attr_group adva_timecard_groups[];
> +
> +static const struct ocp_sma_op ocp_adva_sma_op;
> +
>   struct ptp_ocp_eeprom_map {
>   	u16	off;
>   	u16	len;
> @@ -835,10 +851,122 @@ static struct ocp_resource ocp_art_resource[] = {
>   	{ }
>   };
>   
> +static struct ocp_resource ocp_adva_resource[] = {
> +	{
> +		OCP_MEM_RESOURCE(reg),
> +		.offset = 0x01000000, .size = 0x10000,
> +	},
> +	{
> +		OCP_EXT_RESOURCE(ts0),
> +		.offset = 0x01010000, .size = 0x10000, .irq_vec = 1,
> +		.extra = &(struct ptp_ocp_ext_info) {
> +			.index = 0,
> +			.irq_fcn = ptp_ocp_ts_irq,
> +			.enable = ptp_ocp_ts_enable,
> +		},
> +	},
> +	{
> +		OCP_EXT_RESOURCE(ts1),
> +		.offset = 0x01020000, .size = 0x10000, .irq_vec = 2,
> +		.extra = &(struct ptp_ocp_ext_info) {
> +			.index = 1,
> +			.irq_fcn = ptp_ocp_ts_irq,
> +			.enable = ptp_ocp_ts_enable,
> +		},
> +	},
> +	{
> +		OCP_EXT_RESOURCE(ts2),
> +		.offset = 0x01060000, .size = 0x10000, .irq_vec = 6,
> +		.extra = &(struct ptp_ocp_ext_info) {
> +			.index = 2,
> +			.irq_fcn = ptp_ocp_ts_irq,
> +			.enable = ptp_ocp_ts_enable,
> +		},
> +	},
> +	/* Timestamp for PHC and/or PPS generator */
> +	{
> +		OCP_EXT_RESOURCE(pps),
> +		.offset = 0x010C0000, .size = 0x10000, .irq_vec = 0,
> +		.extra = &(struct ptp_ocp_ext_info) {
> +			.index = 5,
> +			.irq_fcn = ptp_ocp_ts_irq,
> +			.enable = ptp_ocp_ts_enable,
> +		},
> +	},
> +	{
> +		OCP_EXT_RESOURCE(signal_out[0]),
> +		.offset = 0x010D0000, .size = 0x10000, .irq_vec = 11,
> +		.extra = &(struct ptp_ocp_ext_info) {
> +			.index = 1,
> +			.irq_fcn = ptp_ocp_signal_irq,
> +			.enable = ptp_ocp_signal_enable,
> +		},
> +	},
> +	{
> +		OCP_MEM_RESOURCE(pps_to_ext),
> +		.offset = 0x01030000, .size = 0x10000,
> +	},
> +	{
> +		OCP_MEM_RESOURCE(pps_to_clk),
> +		.offset = 0x01040000, .size = 0x10000,
> +	},
> +	{
> +		OCP_MEM_RESOURCE(tod),
> +		.offset = 0x01050000, .size = 0x10000,
> +	},
> +	{
> +		OCP_MEM_RESOURCE(image),
> +		.offset = 0x00020000, .size = 0x1000,
> +	},
> +	{
> +		OCP_MEM_RESOURCE(pps_select),
> +		.offset = 0x00130000, .size = 0x1000,
> +	},
> +	{
> +		OCP_MEM_RESOURCE(sma_map1),
> +		.offset = 0x00140000, .size = 0x1000,
> +	},
> +	{
> +		OCP_MEM_RESOURCE(sma_map2),
> +		.offset = 0x00220000, .size = 0x1000,
> +	},
> +	{
> +		OCP_SERIAL_RESOURCE(gnss_port),
> +		.offset = 0x00160000 + 0x1000, .irq_vec = 3,
> +		.extra = &(struct ptp_ocp_serial_port) {
> +			.baud = 9600,
> +		},
> +	},
> +	{
> +			OCP_MEM_RESOURCE(freq_in[0]),
> +			.offset = 0x01200000, .size = 0x10000,
> +	},
> +	{
> +			OCP_SPI_RESOURCE(spi_flash),
> +			.offset = 0x00310400, .size = 0x10000, .irq_vec = 9,
> +			.extra = &(struct ptp_ocp_flash_info) {
> +				.name = "spi_altera", .pci_offset = 0,
> +				.data_size = sizeof(struct altera_spi_platform_data),
> +				.data = &(struct altera_spi_platform_data) {
> +					.num_chipselect = 1,
> +					.num_devices = 1,
> +					.devices = &(struct spi_board_info) {
> +						.modalias = "spi-nor",
> +					},
> +				},
> +			},
> +	},
> +	{
> +		.setup = ptp_ocp_adva_board_init,
> +	},
> +	{ }
> +};
> +
>   static const struct pci_device_id ptp_ocp_pcidev_id[] = {
>   	{ PCI_DEVICE_DATA(FACEBOOK, TIMECARD, &ocp_fb_resource) },
>   	{ PCI_DEVICE_DATA(CELESTICA, TIMECARD, &ocp_fb_resource) },
>   	{ PCI_DEVICE_DATA(OROLIA, ARTCARD, &ocp_art_resource) },
> +	{ PCI_DEVICE_DATA(ADVA, TIMECARD, &ocp_adva_resource) },
>   	{ }
>   };
>   MODULE_DEVICE_TABLE(pci, ptp_ocp_pcidev_id);
> @@ -917,6 +1045,27 @@ static const struct ocp_selector ptp_ocp_art_sma_out[] = {
>   	{ }
>   };
>   
> +static const struct ocp_selector ptp_ocp_adva_sma_in[] = {
> +	{ .name = "10Mhz",	.value = 0x0000,      .frequency = 10000000},
> +	{ .name = "PPS1",	.value = 0x0001,      .frequency = 1 },
> +	{ .name = "PPS2",	.value = 0x0002,      .frequency = 1 },
> +	{ .name = "TS1",	.value = 0x0004,      .frequency = 0 },
> +	{ .name = "TS2",	.value = 0x0008,      .frequency = 0 },
> +	{ .name = "FREQ1",	.value = 0x0100,      .frequency = 0 },
> +	{ .name = "None",	.value = SMA_DISABLE, .frequency = 0 },
> +	{ }
> +};
> +
> +static const struct ocp_selector ptp_ocp_adva_sma_out[] = {
> +	{ .name = "10Mhz",	.value = 0x0000,  .frequency = 10000000},
> +	{ .name = "PHC",	.value = 0x0001,  .frequency = 1 },
> +	{ .name = "GNSS1",	.value = 0x0004,  .frequency = 1 },
> +	{ .name = "GEN1",	.value = 0x0040 },
> +	{ .name = "GND",	.value = 0x2000 },
> +	{ .name = "VCC",	.value = 0x4000 },
> +	{ }
> +};
> +
>   struct ocp_sma_op {
>   	const struct ocp_selector *tbl[2];
>   	void (*init)(struct ptp_ocp *bp);
> @@ -1363,20 +1512,20 @@ ptp_ocp_estimate_pci_timing(struct ptp_ocp *bp)
>   }
>   
>   static int
> -ptp_ocp_init_clock(struct ptp_ocp *bp)
> +ptp_ocp_init_clock(struct ptp_ocp *bp, struct servo_val *servo_vals)
>   {
>   	struct timespec64 ts;
>   	u32 ctrl;
>   
> +

no need for the second empty line

>   	ctrl = OCP_CTRL_ENABLE;
>   	iowrite32(ctrl, &bp->reg->ctrl);
>   
> -	/* NO DRIFT Correction */
> -	/* offset_p:i 1/8, offset_i: 1/16, drift_p: 0, drift_i: 0 */
> -	iowrite32(0x2000, &bp->reg->servo_offset_p);
> -	iowrite32(0x1000, &bp->reg->servo_offset_i);
> -	iowrite32(0,	  &bp->reg->servo_drift_p);
> -	iowrite32(0,	  &bp->reg->servo_drift_i);
> +	/* servo configuration */
> +	iowrite32(servo_vals->servo_offset_p_val, &bp->reg->servo_offset_p);
> +	iowrite32(servo_vals->servo_offset_i_val, &bp->reg->servo_offset_i);
> +	iowrite32(servo_vals->servo_drift_p_val, &bp->reg->servo_drift_p);
> +	iowrite32(servo_vals->servo_drift_p_val, &bp->reg->servo_drift_i);
>   
>   	/* latch servo values */
>   	ctrl |= OCP_CTRL_ADJUST_SERVO;
> @@ -2362,6 +2511,14 @@ static const struct ocp_sma_op ocp_fb_sma_op = {
>   	.set_output	= ptp_ocp_sma_fb_set_output,
>   };
>   
> +static const struct ocp_sma_op ocp_adva_sma_op = {
> +	.tbl		= { ptp_ocp_adva_sma_in, ptp_ocp_adva_sma_out },
> +	.init		= ptp_ocp_sma_fb_init,
> +	.get		= ptp_ocp_sma_fb_get,
> +	.set_inputs	= ptp_ocp_sma_fb_set_inputs,
> +	.set_output	= ptp_ocp_sma_fb_set_output,
> +};
> +
>   static int
>   ptp_ocp_set_pins(struct ptp_ocp *bp)
>   {
> @@ -2420,6 +2577,7 @@ static int
>   ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
>   {
>   	int err;
> +	struct servo_val servo_vals;
>   
>   	bp->flash_start = 1024 * 4096;
>   	bp->eeprom_map = fb_eeprom_map;
> @@ -2441,7 +2599,14 @@ ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
>   		return err;
>   	ptp_ocp_sma_init(bp);
>   
> -	return ptp_ocp_init_clock(bp);
> +	/* NO DRIFT Correction */
> +	/* offset_p:i 1/8, offset_i: 1/16, drift_p: 0, drift_i: 0 */
> +	servo_vals.servo_offset_p_val = 0x2000;
> +	servo_vals.servo_offset_i_val = 0x1000;
> +	servo_vals.servo_drift_p_val = 0;
> +	servo_vals.servo_drift_p_val = 0;

instead of adding this to every particular initialization function,
struct ptp_ocp_servo_conf can be put to .extra field of the resource
holding init function. This will move all configuration points to the
list of card-specific resources, the place to have differences of cards
and will make the code cleaner and eliminate all these local structs.
We can potentially create another static function to configure servo
part, but it's up to you.

> +
> +	return ptp_ocp_init_clock(bp, &servo_vals);
>   }
>   
>   static bool
> @@ -2583,6 +2748,7 @@ static int
>   ptp_ocp_art_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
>   {
>   	int err;
> +	struct servo_val servo_vals;
>   
>   	bp->flash_start = 0x1000000;
>   	bp->eeprom_map = art_eeprom_map;
> @@ -2603,7 +2769,49 @@ ptp_ocp_art_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
>   	if (err)
>   		return err;
>   
> -	return ptp_ocp_init_clock(bp);
> +	/* NO DRIFT Correction */
> +	/* offset_p:i 1/8, offset_i: 1/16, drift_p: 0, drift_i: 0 */
> +	servo_vals.servo_offset_p_val = 0x2000;
> +	servo_vals.servo_offset_i_val = 0x1000;
> +	servo_vals.servo_drift_p_val = 0;
> +	servo_vals.servo_drift_p_val = 0;
> +
> +	return ptp_ocp_init_clock(bp, &servo_vals);
> +}
> +
> +/* ADVA specific board initializers; last "resource" registered. */
> +static int
> +ptp_ocp_adva_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
> +{
> +	int err;
> +	struct servo_val servo_vals;
> +
> +	bp->flash_start = 0xA00000;
> +	bp->fw_version = ioread32(&bp->image->version);
> +	bp->sma_op = &ocp_adva_sma_op;
> +
> +	ptp_ocp_fb_set_version(bp);
> +
> +	ptp_ocp_tod_init(bp);
> +	ptp_ocp_nmea_out_init(bp);
> +	ptp_ocp_signal_init(bp);
> +
> +	err = ptp_ocp_attr_group_add(bp, adva_timecard_groups);
> +	if (err)
> +		return err;
> +
> +	err = ptp_ocp_set_pins(bp);
> +	if (err)
> +		return err;
> +	ptp_ocp_sma_init(bp);
> +
> +	/* offset_p:i 3/4, offset_i: 1/16, drift_p: 0, drift_i: 0 */
> +	servo_vals.servo_offset_p_val = 0xc000;
> +	servo_vals.servo_offset_i_val = 0x1000;
> +	servo_vals.servo_drift_p_val = 0;
> +	servo_vals.servo_drift_p_val = 0;
> +
> +	return ptp_ocp_init_clock(bp, &servo_vals);
>   }
>   
>   static ssize_t
> @@ -3578,6 +3786,35 @@ static const struct ocp_attr_group art_timecard_groups[] = {
>   	{ },
>   };
>   
> +static struct attribute *adva_timecard_attrs[] = {
> +	&dev_attr_serialnum.attr,
> +	&dev_attr_gnss_sync.attr,
> +	&dev_attr_clock_source.attr,
> +	&dev_attr_available_clock_sources.attr,
> +	&dev_attr_sma1.attr,
> +	&dev_attr_sma2.attr,
> +	&dev_attr_sma3.attr,
> +	&dev_attr_sma4.attr,
> +	&dev_attr_available_sma_inputs.attr,
> +	&dev_attr_available_sma_outputs.attr,
> +	&dev_attr_clock_status_drift.attr,
> +	&dev_attr_clock_status_offset.attr,
> +	&dev_attr_ts_window_adjust.attr,
> +	&dev_attr_tod_correction.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group adva_timecard_group = {
> +	.attrs = adva_timecard_attrs,
> +};
> +
> +static const struct ocp_attr_group adva_timecard_groups[] = {
> +	{ .cap = OCP_CAP_BASIC,	    .group = &adva_timecard_group },
> +	{ .cap = OCP_CAP_SIGNAL,    .group = &fb_timecard_signal0_group },
> +	{ .cap = OCP_CAP_FREQ,	    .group = &fb_timecard_freq0_group },
> +	{ },
> +};
> +
>   static void
>   gpio_input_map(char *buf, struct ptp_ocp *bp, u16 map[][2], u16 bit,
>   	       const char *def)

starting from here ...

> @@ -4492,7 +4729,7 @@ ptp_ocp_remove(struct pci_dev *pdev)
>   	cancel_delayed_work_sync(&bp->sync_work);
>   	for (i = 0; i < OCP_SMA_NUM; i++) {
>   		if (bp->sma[i].dpll_pin) {
> -			dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, bp);
> +			dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, &bp->sma[i]);
>   			dpll_pin_put(bp->sma[i].dpll_pin);
>   		}
>   	}

the chuck is already in a different patch and is reviewed actually, no
need to post it again.
kernel test robot Dec. 24, 2023, 12:57 a.m. UTC | #2
Hi Sagi,

kernel test robot noticed the following build warnings:

[auto build test WARNING on net/main]
[also build test WARNING on net-next/main linus/master v6.7-rc6 next-20231222]
[cannot apply to horms-ipvs/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Sagi-Maimon/ptp-ocp-add-Adva-timecard-support/20231222-182253
base:   net/main
patch link:    https://lore.kernel.org/r/20231221153755.2690-1-maimon.sagi%40gmail.com
patch subject: [PATCH v1] ptp: ocp: add Adva timecard support
config: x86_64-allyesconfig (https://download.01.org/0day-ci/archive/20231224/202312240816.FklJZk9r-lkp@intel.com/config)
compiler: clang version 16.0.4 (https://github.com/llvm/llvm-project.git ae42196bc493ffe877a7e3dff8be32035dea4d07)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231224/202312240816.FklJZk9r-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202312240816.FklJZk9r-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/ptp/ptp_ocp.c:418:32: warning: tentative definition of variable with internal linkage has incomplete non-array type 'const struct ocp_sma_op' [-Wtentative-definition-incomplete-type]
   static const struct ocp_sma_op ocp_adva_sma_op;
                                  ^
   drivers/ptp/ptp_ocp.c:377:15: note: forward declaration of 'struct ocp_sma_op'
           const struct ocp_sma_op *sma_op;
                        ^
   1 warning generated.


vim +418 drivers/ptp/ptp_ocp.c

   417	
 > 418	static const struct ocp_sma_op ocp_adva_sma_op;
   419
Sagi Maimon Dec. 24, 2023, 11:56 a.m. UTC | #3
On Thu, Dec 21, 2023 at 6:56 PM Vadim Fedorenko
<vadim.fedorenko@linux.dev> wrote:
Vadim Thanks for your comments.

>
> On 21/12/2023 15:37, Sagi Maimon wrote:
> > Adding support for the Adva timecard.
> > The card uses different drivers to provide access to the
> > firmware SPI flash (Altera based).
> > Other parts of the code are the same and could be reused.
> >
> > Signed-off-by: Sagi Maimon <maimon.sagi@gmail.com>
> > ---
> >   drivers/ptp/ptp_ocp.c | 257 ++++++++++++++++++++++++++++++++++++++++--
> >   1 file changed, 247 insertions(+), 10 deletions(-)
> >
> > diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
> > index 4021d3d325f9..73e91b8a2887 100644
> > --- a/drivers/ptp/ptp_ocp.c
> > +++ b/drivers/ptp/ptp_ocp.c
> > @@ -34,6 +34,9 @@
> >   #define PCI_VENDOR_ID_OROLIA                        0x1ad7
> >   #define PCI_DEVICE_ID_OROLIA_ARTCARD                0xa000
> >
> > +#define PCI_VENDOR_ID_ADVA                   0xad5a
> > +#define PCI_DEVICE_ID_ADVA_TIMECARD          0x0400
> > +
> >   static struct class timecard_class = {
> >       .name           = "timecard",
> >   };
> > @@ -63,6 +66,13 @@ struct ocp_reg {
> >       u32     status_drift;
> >   };
> >
> > +struct servo_val {
> > +     u32     servo_offset_p_val;
> > +     u32     servo_offset_i_val;
> > +     u32     servo_drift_p_val;
> > +     u32     servo_drift_i_val;
> > +};
> > +
>
> I don't really like naming here. Let's go with ptp_ocp prefix first.
> Then it's more like configuration rather than actual values, so I would
> say ptp_ocp_servo_conf is better here. And let's remove "_val" - no real
> need for this suffix.
>
Will be fixed on patch V2
> >   #define OCP_CTRL_ENABLE             BIT(0)
> >   #define OCP_CTRL_ADJUST_TIME        BIT(1)
> >   #define OCP_CTRL_ADJUST_OFFSET      BIT(2)
> > @@ -401,6 +411,12 @@ static const struct ocp_attr_group fb_timecard_groups[];
> >
> >   static const struct ocp_attr_group art_timecard_groups[];
> >
> > +static int ptp_ocp_adva_board_init(struct ptp_ocp *bp, struct ocp_resource *r);
> > +
> > +static const struct ocp_attr_group adva_timecard_groups[];
> > +
> > +static const struct ocp_sma_op ocp_adva_sma_op;
> > +
> >   struct ptp_ocp_eeprom_map {
> >       u16     off;
> >       u16     len;
> > @@ -835,10 +851,122 @@ static struct ocp_resource ocp_art_resource[] = {
> >       { }
> >   };
> >
> > +static struct ocp_resource ocp_adva_resource[] = {
> > +     {
> > +             OCP_MEM_RESOURCE(reg),
> > +             .offset = 0x01000000, .size = 0x10000,
> > +     },
> > +     {
> > +             OCP_EXT_RESOURCE(ts0),
> > +             .offset = 0x01010000, .size = 0x10000, .irq_vec = 1,
> > +             .extra = &(struct ptp_ocp_ext_info) {
> > +                     .index = 0,
> > +                     .irq_fcn = ptp_ocp_ts_irq,
> > +                     .enable = ptp_ocp_ts_enable,
> > +             },
> > +     },
> > +     {
> > +             OCP_EXT_RESOURCE(ts1),
> > +             .offset = 0x01020000, .size = 0x10000, .irq_vec = 2,
> > +             .extra = &(struct ptp_ocp_ext_info) {
> > +                     .index = 1,
> > +                     .irq_fcn = ptp_ocp_ts_irq,
> > +                     .enable = ptp_ocp_ts_enable,
> > +             },
> > +     },
> > +     {
> > +             OCP_EXT_RESOURCE(ts2),
> > +             .offset = 0x01060000, .size = 0x10000, .irq_vec = 6,
> > +             .extra = &(struct ptp_ocp_ext_info) {
> > +                     .index = 2,
> > +                     .irq_fcn = ptp_ocp_ts_irq,
> > +                     .enable = ptp_ocp_ts_enable,
> > +             },
> > +     },
> > +     /* Timestamp for PHC and/or PPS generator */
> > +     {
> > +             OCP_EXT_RESOURCE(pps),
> > +             .offset = 0x010C0000, .size = 0x10000, .irq_vec = 0,
> > +             .extra = &(struct ptp_ocp_ext_info) {
> > +                     .index = 5,
> > +                     .irq_fcn = ptp_ocp_ts_irq,
> > +                     .enable = ptp_ocp_ts_enable,
> > +             },
> > +     },
> > +     {
> > +             OCP_EXT_RESOURCE(signal_out[0]),
> > +             .offset = 0x010D0000, .size = 0x10000, .irq_vec = 11,
> > +             .extra = &(struct ptp_ocp_ext_info) {
> > +                     .index = 1,
> > +                     .irq_fcn = ptp_ocp_signal_irq,
> > +                     .enable = ptp_ocp_signal_enable,
> > +             },
> > +     },
> > +     {
> > +             OCP_MEM_RESOURCE(pps_to_ext),
> > +             .offset = 0x01030000, .size = 0x10000,
> > +     },
> > +     {
> > +             OCP_MEM_RESOURCE(pps_to_clk),
> > +             .offset = 0x01040000, .size = 0x10000,
> > +     },
> > +     {
> > +             OCP_MEM_RESOURCE(tod),
> > +             .offset = 0x01050000, .size = 0x10000,
> > +     },
> > +     {
> > +             OCP_MEM_RESOURCE(image),
> > +             .offset = 0x00020000, .size = 0x1000,
> > +     },
> > +     {
> > +             OCP_MEM_RESOURCE(pps_select),
> > +             .offset = 0x00130000, .size = 0x1000,
> > +     },
> > +     {
> > +             OCP_MEM_RESOURCE(sma_map1),
> > +             .offset = 0x00140000, .size = 0x1000,
> > +     },
> > +     {
> > +             OCP_MEM_RESOURCE(sma_map2),
> > +             .offset = 0x00220000, .size = 0x1000,
> > +     },
> > +     {
> > +             OCP_SERIAL_RESOURCE(gnss_port),
> > +             .offset = 0x00160000 + 0x1000, .irq_vec = 3,
> > +             .extra = &(struct ptp_ocp_serial_port) {
> > +                     .baud = 9600,
> > +             },
> > +     },
> > +     {
> > +                     OCP_MEM_RESOURCE(freq_in[0]),
> > +                     .offset = 0x01200000, .size = 0x10000,
> > +     },
> > +     {
> > +                     OCP_SPI_RESOURCE(spi_flash),
> > +                     .offset = 0x00310400, .size = 0x10000, .irq_vec = 9,
> > +                     .extra = &(struct ptp_ocp_flash_info) {
> > +                             .name = "spi_altera", .pci_offset = 0,
> > +                             .data_size = sizeof(struct altera_spi_platform_data),
> > +                             .data = &(struct altera_spi_platform_data) {
> > +                                     .num_chipselect = 1,
> > +                                     .num_devices = 1,
> > +                                     .devices = &(struct spi_board_info) {
> > +                                             .modalias = "spi-nor",
> > +                                     },
> > +                             },
> > +                     },
> > +     },
> > +     {
> > +             .setup = ptp_ocp_adva_board_init,
> > +     },
> > +     { }
> > +};
> > +
> >   static const struct pci_device_id ptp_ocp_pcidev_id[] = {
> >       { PCI_DEVICE_DATA(FACEBOOK, TIMECARD, &ocp_fb_resource) },
> >       { PCI_DEVICE_DATA(CELESTICA, TIMECARD, &ocp_fb_resource) },
> >       { PCI_DEVICE_DATA(OROLIA, ARTCARD, &ocp_art_resource) },
> > +     { PCI_DEVICE_DATA(ADVA, TIMECARD, &ocp_adva_resource) },
> >       { }
> >   };
> >   MODULE_DEVICE_TABLE(pci, ptp_ocp_pcidev_id);
> > @@ -917,6 +1045,27 @@ static const struct ocp_selector ptp_ocp_art_sma_out[] = {
> >       { }
> >   };
> >
> > +static const struct ocp_selector ptp_ocp_adva_sma_in[] = {
> > +     { .name = "10Mhz",      .value = 0x0000,      .frequency = 10000000},
> > +     { .name = "PPS1",       .value = 0x0001,      .frequency = 1 },
> > +     { .name = "PPS2",       .value = 0x0002,      .frequency = 1 },
> > +     { .name = "TS1",        .value = 0x0004,      .frequency = 0 },
> > +     { .name = "TS2",        .value = 0x0008,      .frequency = 0 },
> > +     { .name = "FREQ1",      .value = 0x0100,      .frequency = 0 },
> > +     { .name = "None",       .value = SMA_DISABLE, .frequency = 0 },
> > +     { }
> > +};
> > +
> > +static const struct ocp_selector ptp_ocp_adva_sma_out[] = {
> > +     { .name = "10Mhz",      .value = 0x0000,  .frequency = 10000000},
> > +     { .name = "PHC",        .value = 0x0001,  .frequency = 1 },
> > +     { .name = "GNSS1",      .value = 0x0004,  .frequency = 1 },
> > +     { .name = "GEN1",       .value = 0x0040 },
> > +     { .name = "GND",        .value = 0x2000 },
> > +     { .name = "VCC",        .value = 0x4000 },
> > +     { }
> > +};
> > +
> >   struct ocp_sma_op {
> >       const struct ocp_selector *tbl[2];
> >       void (*init)(struct ptp_ocp *bp);
> > @@ -1363,20 +1512,20 @@ ptp_ocp_estimate_pci_timing(struct ptp_ocp *bp)
> >   }
> >
> >   static int
> > -ptp_ocp_init_clock(struct ptp_ocp *bp)
> > +ptp_ocp_init_clock(struct ptp_ocp *bp, struct servo_val *servo_vals)
> >   {
> >       struct timespec64 ts;
> >       u32 ctrl;
> >
> > +
>
> no need for the second empty line
>
Will be fixed on patch V2

> >       ctrl = OCP_CTRL_ENABLE;
> >       iowrite32(ctrl, &bp->reg->ctrl);
> >
> > -     /* NO DRIFT Correction */
> > -     /* offset_p:i 1/8, offset_i: 1/16, drift_p: 0, drift_i: 0 */
> > -     iowrite32(0x2000, &bp->reg->servo_offset_p);
> > -     iowrite32(0x1000, &bp->reg->servo_offset_i);
> > -     iowrite32(0,      &bp->reg->servo_drift_p);
> > -     iowrite32(0,      &bp->reg->servo_drift_i);
> > +     /* servo configuration */
> > +     iowrite32(servo_vals->servo_offset_p_val, &bp->reg->servo_offset_p);
> > +     iowrite32(servo_vals->servo_offset_i_val, &bp->reg->servo_offset_i);
> > +     iowrite32(servo_vals->servo_drift_p_val, &bp->reg->servo_drift_p);
> > +     iowrite32(servo_vals->servo_drift_p_val, &bp->reg->servo_drift_i);
> >
> >       /* latch servo values */
> >       ctrl |= OCP_CTRL_ADJUST_SERVO;
> > @@ -2362,6 +2511,14 @@ static const struct ocp_sma_op ocp_fb_sma_op = {
> >       .set_output     = ptp_ocp_sma_fb_set_output,
> >   };
> >
> > +static const struct ocp_sma_op ocp_adva_sma_op = {
> > +     .tbl            = { ptp_ocp_adva_sma_in, ptp_ocp_adva_sma_out },
> > +     .init           = ptp_ocp_sma_fb_init,
> > +     .get            = ptp_ocp_sma_fb_get,
> > +     .set_inputs     = ptp_ocp_sma_fb_set_inputs,
> > +     .set_output     = ptp_ocp_sma_fb_set_output,
> > +};
> > +
> >   static int
> >   ptp_ocp_set_pins(struct ptp_ocp *bp)
> >   {
> > @@ -2420,6 +2577,7 @@ static int
> >   ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
> >   {
> >       int err;
> > +     struct servo_val servo_vals;
> >
> >       bp->flash_start = 1024 * 4096;
> >       bp->eeprom_map = fb_eeprom_map;
> > @@ -2441,7 +2599,14 @@ ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
> >               return err;
> >       ptp_ocp_sma_init(bp);
> >
> > -     return ptp_ocp_init_clock(bp);
> > +     /* NO DRIFT Correction */
> > +     /* offset_p:i 1/8, offset_i: 1/16, drift_p: 0, drift_i: 0 */
> > +     servo_vals.servo_offset_p_val = 0x2000;
> > +     servo_vals.servo_offset_i_val = 0x1000;
> > +     servo_vals.servo_drift_p_val = 0;
> > +     servo_vals.servo_drift_p_val = 0;
>
> instead of adding this to every particular initialization function,
> struct ptp_ocp_servo_conf can be put to .extra field of the resource
> holding init function. This will move all configuration points to the
> list of card-specific resources, the place to have differences of cards
> and will make the code cleaner and eliminate all these local structs.
> We can potentially create another static function to configure servo
> part, but it's up to you.
>
Will be done on patch V2
> > +
> > +     return ptp_ocp_init_clock(bp, &servo_vals);
> >   }
> >
> >   static bool
> > @@ -2583,6 +2748,7 @@ static int
> >   ptp_ocp_art_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
> >   {
> >       int err;
> > +     struct servo_val servo_vals;
> >
> >       bp->flash_start = 0x1000000;
> >       bp->eeprom_map = art_eeprom_map;
> > @@ -2603,7 +2769,49 @@ ptp_ocp_art_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
> >       if (err)
> >               return err;
> >
> > -     return ptp_ocp_init_clock(bp);
> > +     /* NO DRIFT Correction */
> > +     /* offset_p:i 1/8, offset_i: 1/16, drift_p: 0, drift_i: 0 */
> > +     servo_vals.servo_offset_p_val = 0x2000;
> > +     servo_vals.servo_offset_i_val = 0x1000;
> > +     servo_vals.servo_drift_p_val = 0;
> > +     servo_vals.servo_drift_p_val = 0;
> > +
> > +     return ptp_ocp_init_clock(bp, &servo_vals);
> > +}
> > +
> > +/* ADVA specific board initializers; last "resource" registered. */
> > +static int
> > +ptp_ocp_adva_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
> > +{
> > +     int err;
> > +     struct servo_val servo_vals;
> > +
> > +     bp->flash_start = 0xA00000;
> > +     bp->fw_version = ioread32(&bp->image->version);
> > +     bp->sma_op = &ocp_adva_sma_op;
> > +
> > +     ptp_ocp_fb_set_version(bp);
> > +
> > +     ptp_ocp_tod_init(bp);
> > +     ptp_ocp_nmea_out_init(bp);
> > +     ptp_ocp_signal_init(bp);
> > +
> > +     err = ptp_ocp_attr_group_add(bp, adva_timecard_groups);
> > +     if (err)
> > +             return err;
> > +
> > +     err = ptp_ocp_set_pins(bp);
> > +     if (err)
> > +             return err;
> > +     ptp_ocp_sma_init(bp);
> > +
> > +     /* offset_p:i 3/4, offset_i: 1/16, drift_p: 0, drift_i: 0 */
> > +     servo_vals.servo_offset_p_val = 0xc000;
> > +     servo_vals.servo_offset_i_val = 0x1000;
> > +     servo_vals.servo_drift_p_val = 0;
> > +     servo_vals.servo_drift_p_val = 0;
> > +
> > +     return ptp_ocp_init_clock(bp, &servo_vals);
> >   }
> >
> >   static ssize_t
> > @@ -3578,6 +3786,35 @@ static const struct ocp_attr_group art_timecard_groups[] = {
> >       { },
> >   };
> >
> > +static struct attribute *adva_timecard_attrs[] = {
> > +     &dev_attr_serialnum.attr,
> > +     &dev_attr_gnss_sync.attr,
> > +     &dev_attr_clock_source.attr,
> > +     &dev_attr_available_clock_sources.attr,
> > +     &dev_attr_sma1.attr,
> > +     &dev_attr_sma2.attr,
> > +     &dev_attr_sma3.attr,
> > +     &dev_attr_sma4.attr,
> > +     &dev_attr_available_sma_inputs.attr,
> > +     &dev_attr_available_sma_outputs.attr,
> > +     &dev_attr_clock_status_drift.attr,
> > +     &dev_attr_clock_status_offset.attr,
> > +     &dev_attr_ts_window_adjust.attr,
> > +     &dev_attr_tod_correction.attr,
> > +     NULL,
> > +};
> > +
> > +static const struct attribute_group adva_timecard_group = {
> > +     .attrs = adva_timecard_attrs,
> > +};
> > +
> > +static const struct ocp_attr_group adva_timecard_groups[] = {
> > +     { .cap = OCP_CAP_BASIC,     .group = &adva_timecard_group },
> > +     { .cap = OCP_CAP_SIGNAL,    .group = &fb_timecard_signal0_group },
> > +     { .cap = OCP_CAP_FREQ,      .group = &fb_timecard_freq0_group },
> > +     { },
> > +};
> > +
> >   static void
> >   gpio_input_map(char *buf, struct ptp_ocp *bp, u16 map[][2], u16 bit,
> >              const char *def)
>
> starting from here ...
>
> > @@ -4492,7 +4729,7 @@ ptp_ocp_remove(struct pci_dev *pdev)
> >       cancel_delayed_work_sync(&bp->sync_work);
> >       for (i = 0; i < OCP_SMA_NUM; i++) {
> >               if (bp->sma[i].dpll_pin) {
> > -                     dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, bp);
> > +                     dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, &bp->sma[i]);
> >                       dpll_pin_put(bp->sma[i].dpll_pin);
> >               }
> >       }
>
> the chuck is already in a different patch and is reviewed actually, no
> need to post it again.

Will be fixed on patch V2
diff mbox series

Patch

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 4021d3d325f9..73e91b8a2887 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -34,6 +34,9 @@ 
 #define PCI_VENDOR_ID_OROLIA			0x1ad7
 #define PCI_DEVICE_ID_OROLIA_ARTCARD		0xa000
 
+#define PCI_VENDOR_ID_ADVA			0xad5a
+#define PCI_DEVICE_ID_ADVA_TIMECARD		0x0400
+
 static struct class timecard_class = {
 	.name		= "timecard",
 };
@@ -63,6 +66,13 @@  struct ocp_reg {
 	u32	status_drift;
 };
 
+struct servo_val {
+	u32	servo_offset_p_val;
+	u32	servo_offset_i_val;
+	u32	servo_drift_p_val;
+	u32	servo_drift_i_val;
+};
+
 #define OCP_CTRL_ENABLE		BIT(0)
 #define OCP_CTRL_ADJUST_TIME	BIT(1)
 #define OCP_CTRL_ADJUST_OFFSET	BIT(2)
@@ -401,6 +411,12 @@  static const struct ocp_attr_group fb_timecard_groups[];
 
 static const struct ocp_attr_group art_timecard_groups[];
 
+static int ptp_ocp_adva_board_init(struct ptp_ocp *bp, struct ocp_resource *r);
+
+static const struct ocp_attr_group adva_timecard_groups[];
+
+static const struct ocp_sma_op ocp_adva_sma_op;
+
 struct ptp_ocp_eeprom_map {
 	u16	off;
 	u16	len;
@@ -835,10 +851,122 @@  static struct ocp_resource ocp_art_resource[] = {
 	{ }
 };
 
+static struct ocp_resource ocp_adva_resource[] = {
+	{
+		OCP_MEM_RESOURCE(reg),
+		.offset = 0x01000000, .size = 0x10000,
+	},
+	{
+		OCP_EXT_RESOURCE(ts0),
+		.offset = 0x01010000, .size = 0x10000, .irq_vec = 1,
+		.extra = &(struct ptp_ocp_ext_info) {
+			.index = 0,
+			.irq_fcn = ptp_ocp_ts_irq,
+			.enable = ptp_ocp_ts_enable,
+		},
+	},
+	{
+		OCP_EXT_RESOURCE(ts1),
+		.offset = 0x01020000, .size = 0x10000, .irq_vec = 2,
+		.extra = &(struct ptp_ocp_ext_info) {
+			.index = 1,
+			.irq_fcn = ptp_ocp_ts_irq,
+			.enable = ptp_ocp_ts_enable,
+		},
+	},
+	{
+		OCP_EXT_RESOURCE(ts2),
+		.offset = 0x01060000, .size = 0x10000, .irq_vec = 6,
+		.extra = &(struct ptp_ocp_ext_info) {
+			.index = 2,
+			.irq_fcn = ptp_ocp_ts_irq,
+			.enable = ptp_ocp_ts_enable,
+		},
+	},
+	/* Timestamp for PHC and/or PPS generator */
+	{
+		OCP_EXT_RESOURCE(pps),
+		.offset = 0x010C0000, .size = 0x10000, .irq_vec = 0,
+		.extra = &(struct ptp_ocp_ext_info) {
+			.index = 5,
+			.irq_fcn = ptp_ocp_ts_irq,
+			.enable = ptp_ocp_ts_enable,
+		},
+	},
+	{
+		OCP_EXT_RESOURCE(signal_out[0]),
+		.offset = 0x010D0000, .size = 0x10000, .irq_vec = 11,
+		.extra = &(struct ptp_ocp_ext_info) {
+			.index = 1,
+			.irq_fcn = ptp_ocp_signal_irq,
+			.enable = ptp_ocp_signal_enable,
+		},
+	},
+	{
+		OCP_MEM_RESOURCE(pps_to_ext),
+		.offset = 0x01030000, .size = 0x10000,
+	},
+	{
+		OCP_MEM_RESOURCE(pps_to_clk),
+		.offset = 0x01040000, .size = 0x10000,
+	},
+	{
+		OCP_MEM_RESOURCE(tod),
+		.offset = 0x01050000, .size = 0x10000,
+	},
+	{
+		OCP_MEM_RESOURCE(image),
+		.offset = 0x00020000, .size = 0x1000,
+	},
+	{
+		OCP_MEM_RESOURCE(pps_select),
+		.offset = 0x00130000, .size = 0x1000,
+	},
+	{
+		OCP_MEM_RESOURCE(sma_map1),
+		.offset = 0x00140000, .size = 0x1000,
+	},
+	{
+		OCP_MEM_RESOURCE(sma_map2),
+		.offset = 0x00220000, .size = 0x1000,
+	},
+	{
+		OCP_SERIAL_RESOURCE(gnss_port),
+		.offset = 0x00160000 + 0x1000, .irq_vec = 3,
+		.extra = &(struct ptp_ocp_serial_port) {
+			.baud = 9600,
+		},
+	},
+	{
+			OCP_MEM_RESOURCE(freq_in[0]),
+			.offset = 0x01200000, .size = 0x10000,
+	},
+	{
+			OCP_SPI_RESOURCE(spi_flash),
+			.offset = 0x00310400, .size = 0x10000, .irq_vec = 9,
+			.extra = &(struct ptp_ocp_flash_info) {
+				.name = "spi_altera", .pci_offset = 0,
+				.data_size = sizeof(struct altera_spi_platform_data),
+				.data = &(struct altera_spi_platform_data) {
+					.num_chipselect = 1,
+					.num_devices = 1,
+					.devices = &(struct spi_board_info) {
+						.modalias = "spi-nor",
+					},
+				},
+			},
+	},
+	{
+		.setup = ptp_ocp_adva_board_init,
+	},
+	{ }
+};
+
 static const struct pci_device_id ptp_ocp_pcidev_id[] = {
 	{ PCI_DEVICE_DATA(FACEBOOK, TIMECARD, &ocp_fb_resource) },
 	{ PCI_DEVICE_DATA(CELESTICA, TIMECARD, &ocp_fb_resource) },
 	{ PCI_DEVICE_DATA(OROLIA, ARTCARD, &ocp_art_resource) },
+	{ PCI_DEVICE_DATA(ADVA, TIMECARD, &ocp_adva_resource) },
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, ptp_ocp_pcidev_id);
@@ -917,6 +1045,27 @@  static const struct ocp_selector ptp_ocp_art_sma_out[] = {
 	{ }
 };
 
+static const struct ocp_selector ptp_ocp_adva_sma_in[] = {
+	{ .name = "10Mhz",	.value = 0x0000,      .frequency = 10000000},
+	{ .name = "PPS1",	.value = 0x0001,      .frequency = 1 },
+	{ .name = "PPS2",	.value = 0x0002,      .frequency = 1 },
+	{ .name = "TS1",	.value = 0x0004,      .frequency = 0 },
+	{ .name = "TS2",	.value = 0x0008,      .frequency = 0 },
+	{ .name = "FREQ1",	.value = 0x0100,      .frequency = 0 },
+	{ .name = "None",	.value = SMA_DISABLE, .frequency = 0 },
+	{ }
+};
+
+static const struct ocp_selector ptp_ocp_adva_sma_out[] = {
+	{ .name = "10Mhz",	.value = 0x0000,  .frequency = 10000000},
+	{ .name = "PHC",	.value = 0x0001,  .frequency = 1 },
+	{ .name = "GNSS1",	.value = 0x0004,  .frequency = 1 },
+	{ .name = "GEN1",	.value = 0x0040 },
+	{ .name = "GND",	.value = 0x2000 },
+	{ .name = "VCC",	.value = 0x4000 },
+	{ }
+};
+
 struct ocp_sma_op {
 	const struct ocp_selector *tbl[2];
 	void (*init)(struct ptp_ocp *bp);
@@ -1363,20 +1512,20 @@  ptp_ocp_estimate_pci_timing(struct ptp_ocp *bp)
 }
 
 static int
-ptp_ocp_init_clock(struct ptp_ocp *bp)
+ptp_ocp_init_clock(struct ptp_ocp *bp, struct servo_val *servo_vals)
 {
 	struct timespec64 ts;
 	u32 ctrl;
 
+
 	ctrl = OCP_CTRL_ENABLE;
 	iowrite32(ctrl, &bp->reg->ctrl);
 
-	/* NO DRIFT Correction */
-	/* offset_p:i 1/8, offset_i: 1/16, drift_p: 0, drift_i: 0 */
-	iowrite32(0x2000, &bp->reg->servo_offset_p);
-	iowrite32(0x1000, &bp->reg->servo_offset_i);
-	iowrite32(0,	  &bp->reg->servo_drift_p);
-	iowrite32(0,	  &bp->reg->servo_drift_i);
+	/* servo configuration */
+	iowrite32(servo_vals->servo_offset_p_val, &bp->reg->servo_offset_p);
+	iowrite32(servo_vals->servo_offset_i_val, &bp->reg->servo_offset_i);
+	iowrite32(servo_vals->servo_drift_p_val, &bp->reg->servo_drift_p);
+	iowrite32(servo_vals->servo_drift_p_val, &bp->reg->servo_drift_i);
 
 	/* latch servo values */
 	ctrl |= OCP_CTRL_ADJUST_SERVO;
@@ -2362,6 +2511,14 @@  static const struct ocp_sma_op ocp_fb_sma_op = {
 	.set_output	= ptp_ocp_sma_fb_set_output,
 };
 
+static const struct ocp_sma_op ocp_adva_sma_op = {
+	.tbl		= { ptp_ocp_adva_sma_in, ptp_ocp_adva_sma_out },
+	.init		= ptp_ocp_sma_fb_init,
+	.get		= ptp_ocp_sma_fb_get,
+	.set_inputs	= ptp_ocp_sma_fb_set_inputs,
+	.set_output	= ptp_ocp_sma_fb_set_output,
+};
+
 static int
 ptp_ocp_set_pins(struct ptp_ocp *bp)
 {
@@ -2420,6 +2577,7 @@  static int
 ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
 {
 	int err;
+	struct servo_val servo_vals;
 
 	bp->flash_start = 1024 * 4096;
 	bp->eeprom_map = fb_eeprom_map;
@@ -2441,7 +2599,14 @@  ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
 		return err;
 	ptp_ocp_sma_init(bp);
 
-	return ptp_ocp_init_clock(bp);
+	/* NO DRIFT Correction */
+	/* offset_p:i 1/8, offset_i: 1/16, drift_p: 0, drift_i: 0 */
+	servo_vals.servo_offset_p_val = 0x2000;
+	servo_vals.servo_offset_i_val = 0x1000;
+	servo_vals.servo_drift_p_val = 0;
+	servo_vals.servo_drift_p_val = 0;
+
+	return ptp_ocp_init_clock(bp, &servo_vals);
 }
 
 static bool
@@ -2583,6 +2748,7 @@  static int
 ptp_ocp_art_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
 {
 	int err;
+	struct servo_val servo_vals;
 
 	bp->flash_start = 0x1000000;
 	bp->eeprom_map = art_eeprom_map;
@@ -2603,7 +2769,49 @@  ptp_ocp_art_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
 	if (err)
 		return err;
 
-	return ptp_ocp_init_clock(bp);
+	/* NO DRIFT Correction */
+	/* offset_p:i 1/8, offset_i: 1/16, drift_p: 0, drift_i: 0 */
+	servo_vals.servo_offset_p_val = 0x2000;
+	servo_vals.servo_offset_i_val = 0x1000;
+	servo_vals.servo_drift_p_val = 0;
+	servo_vals.servo_drift_p_val = 0;
+
+	return ptp_ocp_init_clock(bp, &servo_vals);
+}
+
+/* ADVA specific board initializers; last "resource" registered. */
+static int
+ptp_ocp_adva_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
+{
+	int err;
+	struct servo_val servo_vals;
+
+	bp->flash_start = 0xA00000;
+	bp->fw_version = ioread32(&bp->image->version);
+	bp->sma_op = &ocp_adva_sma_op;
+
+	ptp_ocp_fb_set_version(bp);
+
+	ptp_ocp_tod_init(bp);
+	ptp_ocp_nmea_out_init(bp);
+	ptp_ocp_signal_init(bp);
+
+	err = ptp_ocp_attr_group_add(bp, adva_timecard_groups);
+	if (err)
+		return err;
+
+	err = ptp_ocp_set_pins(bp);
+	if (err)
+		return err;
+	ptp_ocp_sma_init(bp);
+
+	/* offset_p:i 3/4, offset_i: 1/16, drift_p: 0, drift_i: 0 */
+	servo_vals.servo_offset_p_val = 0xc000;
+	servo_vals.servo_offset_i_val = 0x1000;
+	servo_vals.servo_drift_p_val = 0;
+	servo_vals.servo_drift_p_val = 0;
+
+	return ptp_ocp_init_clock(bp, &servo_vals);
 }
 
 static ssize_t
@@ -3578,6 +3786,35 @@  static const struct ocp_attr_group art_timecard_groups[] = {
 	{ },
 };
 
+static struct attribute *adva_timecard_attrs[] = {
+	&dev_attr_serialnum.attr,
+	&dev_attr_gnss_sync.attr,
+	&dev_attr_clock_source.attr,
+	&dev_attr_available_clock_sources.attr,
+	&dev_attr_sma1.attr,
+	&dev_attr_sma2.attr,
+	&dev_attr_sma3.attr,
+	&dev_attr_sma4.attr,
+	&dev_attr_available_sma_inputs.attr,
+	&dev_attr_available_sma_outputs.attr,
+	&dev_attr_clock_status_drift.attr,
+	&dev_attr_clock_status_offset.attr,
+	&dev_attr_ts_window_adjust.attr,
+	&dev_attr_tod_correction.attr,
+	NULL,
+};
+
+static const struct attribute_group adva_timecard_group = {
+	.attrs = adva_timecard_attrs,
+};
+
+static const struct ocp_attr_group adva_timecard_groups[] = {
+	{ .cap = OCP_CAP_BASIC,	    .group = &adva_timecard_group },
+	{ .cap = OCP_CAP_SIGNAL,    .group = &fb_timecard_signal0_group },
+	{ .cap = OCP_CAP_FREQ,	    .group = &fb_timecard_freq0_group },
+	{ },
+};
+
 static void
 gpio_input_map(char *buf, struct ptp_ocp *bp, u16 map[][2], u16 bit,
 	       const char *def)
@@ -4492,7 +4729,7 @@  ptp_ocp_remove(struct pci_dev *pdev)
 	cancel_delayed_work_sync(&bp->sync_work);
 	for (i = 0; i < OCP_SMA_NUM; i++) {
 		if (bp->sma[i].dpll_pin) {
-			dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, bp);
+			dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, &bp->sma[i]);
 			dpll_pin_put(bp->sma[i].dpll_pin);
 		}
 	}