Commit 1aa66a3a authored by Jonathan Lemon's avatar Jonathan Lemon Committed by David S. Miller
Browse files

ptp: ocp: Program the signal generators via PTP_CLK_REQ_PEROUT



The signal generators can be programmed either via the sysfs
file or through a PTP_CLK_REQ_PEROUT ioctl request.

Signed-off-by: default avatarJonathan Lemon <jonathan.lemon@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b325af3c
Loading
Loading
Loading
Loading
+94 −9
Original line number Diff line number Diff line
@@ -332,6 +332,8 @@ static int ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r);
static irqreturn_t ptp_ocp_ts_irq(int irq, void *priv);
static irqreturn_t ptp_ocp_signal_irq(int irq, void *priv);
static int ptp_ocp_ts_enable(void *priv, u32 req, bool enable);
static int ptp_ocp_signal_from_perout(struct ptp_ocp *bp, int gen,
				      struct ptp_perout_request *req);
static int ptp_ocp_signal_enable(void *priv, u32 req, bool enable);
static int ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr);

@@ -867,13 +869,27 @@ ptp_ocp_enable(struct ptp_clock_info *ptp_info, struct ptp_clock_request *rq,
		ext = bp->pps;
		break;
	case PTP_CLK_REQ_PEROUT:
		if (on &&
		    (rq->perout.period.sec != 1 || rq->perout.period.nsec != 0))
			return -EINVAL;
		switch (rq->perout.index) {
		case 0:
			/* This is a request for 1PPS on an output SMA.
			 * Allow, but assume manual configuration.
			 */
			if (on && (rq->perout.period.sec != 1 ||
				   rq->perout.period.nsec != 0))
				return -EINVAL;
			return 0;
		case 1:
		case 2:
		case 3:
		case 4:
			req = rq->perout.index - 1;
			ext = bp->signal_out[req];
			err = ptp_ocp_signal_from_perout(bp, req, &rq->perout);
			if (err)
				return err;
			break;
		}
		break;
	default:
		return -EOPNOTSUPP;
	}
@@ -885,6 +901,24 @@ ptp_ocp_enable(struct ptp_clock_info *ptp_info, struct ptp_clock_request *rq,
	return err;
}

static int
ptp_ocp_verify(struct ptp_clock_info *ptp_info, unsigned pin,
	       enum ptp_pin_function func, unsigned chan)
{
	struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info);
	char buf[16];

	if (func != PTP_PF_PEROUT)
		return -EOPNOTSUPP;

	if (chan)
		sprintf(buf, "OUT: GEN%d", chan);
	else
		sprintf(buf, "OUT: PHC");

	return ptp_ocp_sma_store(bp, buf, pin + 1);
}

static const struct ptp_clock_info ptp_ocp_clock_info = {
	.owner		= THIS_MODULE,
	.name		= KBUILD_MODNAME,
@@ -895,9 +929,10 @@ static const struct ptp_clock_info ptp_ocp_clock_info = {
	.adjfine	= ptp_ocp_null_adjfine,
	.adjphase	= ptp_ocp_null_adjphase,
	.enable		= ptp_ocp_enable,
	.verify		= ptp_ocp_verify,
	.pps		= true,
	.n_ext_ts	= 4,
	.n_per_out	= 1,
	.n_per_out	= 5,
};

static void
@@ -1465,6 +1500,30 @@ ptp_ocp_signal_set(struct ptp_ocp *bp, int gen, struct ptp_ocp_signal *s)
	return 0;
}

static int
ptp_ocp_signal_from_perout(struct ptp_ocp *bp, int gen,
			   struct ptp_perout_request *req)
{
	struct ptp_ocp_signal s = { };

	s.polarity = bp->signal[gen].polarity;
	s.period = ktime_set(req->period.sec, req->period.nsec);
	if (!s.period)
		return 0;

	if (req->flags & PTP_PEROUT_DUTY_CYCLE) {
		s.pulse = ktime_set(req->on.sec, req->on.nsec);
		s.duty = ktime_divns(s.pulse * 100, s.period);
	}

	if (req->flags & PTP_PEROUT_PHASE)
		s.phase = ktime_set(req->phase.sec, req->phase.nsec);
	else
		s.start = ktime_set(req->start.sec, req->start.nsec);

	return ptp_ocp_signal_set(bp, gen, &s);
}

static int
ptp_ocp_signal_enable(void *priv, u32 req, bool enable)
{
@@ -1740,11 +1799,32 @@ ptp_ocp_sma_init(struct ptp_ocp *bp)
	}
}

static int
ptp_ocp_fb_set_pins(struct ptp_ocp *bp)
{
	struct ptp_pin_desc *config;
	int i;

	config = kzalloc(sizeof(*config) * 4, GFP_KERNEL);
	if (!config)
		return -ENOMEM;

	for (i = 0; i < 4; i++) {
		sprintf(config[i].name, "sma%d", i + 1);
		config[i].index = i;
	}

	bp->ptp_info.n_pins = 4;
	bp->ptp_info.pin_config = config;

	return 0;
}

/* FB specific board initializers; last "resource" registered. */
static int
ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
{
	int ver;
	int ver, err;

	bp->flash_start = 1024 * 4096;
	bp->eeprom_map = fb_eeprom_map;
@@ -1761,6 +1841,10 @@ ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
	ptp_ocp_sma_init(bp);
	ptp_ocp_signal_init(bp);

	err = ptp_ocp_fb_set_pins(bp);
	if (err)
		return err;

	return ptp_ocp_init_clock(bp);
}

@@ -3238,6 +3322,7 @@ ptp_ocp_detach(struct ptp_ocp *bp)
		pci_free_irq_vectors(bp->pdev);
	if (bp->ptp)
		ptp_clock_unregister(bp->ptp);
	kfree(bp->ptp_info.pin_config);
	device_unregister(&bp->dev);
}