/*
   forward-ethernet-ptp.c - Ethernet PTP clock for SoftLab-NSK Forward boards

   Copyright (C) 2017 - 2024 SoftLab-NSK <forward@softlab.tv>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "forward.h"
#include "forward-ethernet.h"
#include "forward-pll.h"

static int forward_adjfine(struct ptp_clock_info *ptp, long delta)
{
	struct forward_ethernet_board *brd =
		container_of(ptp, struct forward_ethernet_board, ptp_clock_info);
	return brd->ops->ptp_adjfine(brd, (s64)delta);
}

static int forward_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
	struct forward_ethernet_board *brd =
		container_of(ptp, struct forward_ethernet_board, ptp_clock_info);
	return brd->ops->ptp_adjtime(brd, delta);
}

static int forward_gettimex(struct ptp_clock_info *ptp, struct timespec64 *ts,
			    struct ptp_system_timestamp *sts)
{
	struct forward_ethernet_board *brd =
		container_of(ptp, struct forward_ethernet_board, ptp_clock_info);
	return brd->ops->ptp_gettimex(brd, ts, sts);
}

static int forward_settime(struct ptp_clock_info *ptp, const struct timespec64 *ts)
{
	struct forward_ethernet_board *brd =
		container_of(ptp, struct forward_ethernet_board, ptp_clock_info);
	return brd->ops->ptp_settime(brd, ts);
}

static int forward_enable(struct ptp_clock_info *ptp, struct ptp_clock_request *request, int on)
{
	return -EOPNOTSUPP;
}

static const struct ptp_clock_info forward_ptp_clock_info = {
	.owner = THIS_MODULE,
	.max_adj = 500000,
	.n_alarm = 0,
	.n_ext_ts = 0,
	.n_per_out = 0,
	.n_pins = 0,
	.pps = 0,
	.adjfine = forward_adjfine,
	.adjtime = forward_adjtime,
	.gettimex64 = forward_gettimex,
	.settime64 = forward_settime,
	.enable = forward_enable,
};

void forward_ethernet_ptp_init(struct forward_ethernet_board *brd)
{
	brd->ptp_clock_info = forward_ptp_clock_info;

	snprintf(brd->ptp_clock_info.name, sizeof(brd->ptp_clock_info.name), "%s",
		 brd->dev->dev_name);

	brd->ptp_clock = ptp_clock_register(&brd->ptp_clock_info, brd->dev->dev);
	if (IS_ERR(brd->ptp_clock)) {
		forward_err(brd->dev, "Cannot create PTP clock");
		brd->ptp_clock = NULL;
	}

	brd->ops->ptp_adjfine(brd, 0);
}

void forward_ethernet_ptp_remove(struct forward_ethernet_board *brd)
{
	if (brd->ptp_clock) {
		ptp_clock_unregister(brd->ptp_clock);
		brd->ptp_clock = NULL;
	}
}
