Commit 2cb2cad0 authored by Alessandro Rubini's avatar Alessandro Rubini

time: function to get and set hw time (not working)

parent 650c907b
......@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/list.h>
......@@ -114,7 +115,7 @@ static struct modlist mods[] = {
{"gpio-default", fd_gpio_defaults},
{"reset-again", fd_reset_again},
SUBSYS(acam),
//SUBSYS(time),
SUBSYS(time),
//SUBSYS(i2c),
//SUBSYS(zio),
};
......@@ -132,6 +133,7 @@ int fd_probe(struct spec_dev *dev)
pr_err("%s: can't allocate device\n", __func__);
return -ENOMEM;
}
spin_lock_init(&fd->lock);
dev->sub_priv = fd;
fd->spec = dev;
fd->base = dev->remap[0];
......@@ -165,6 +167,19 @@ int fd_probe(struct spec_dev *dev)
/* Finally, enable the input */
fd_writel(fd, FD_GCR_INPUT_EN, FD_REG_GCR);
if (1) {
struct timespec ts1, ts2, ts3;
/* Temporarily, test the time stuff */
fd_time_set(fd, NULL, NULL);
fd_time_get(fd, NULL, &ts1);
msleep(100);
fd_time_get(fd, NULL, &ts2);
getnstimeofday(&ts3);
printk("%li.%li\n%li.%li\n%li.%li\n",
ts1.tv_sec, ts1.tv_nsec,
ts2.tv_sec, ts2.tv_nsec,
ts3.tv_sec, ts3.tv_nsec);
}
return 0;
err:
......
......@@ -42,6 +42,16 @@ struct spec_fd {
int temp; /* scaled by 4 bits */
};
/* Internal time: the first three fields are just converted to zio time */
struct fd_time {
int64_t utc;
int32_t coarse;
int32_t frac;
int channel;
uint16_t seq_id;
};
static inline uint32_t fd_readl(struct spec_fd *fd, unsigned long reg)
{
return readl(fd->regs + reg);
......@@ -134,6 +144,16 @@ extern void fd_gpio_set_clr(struct spec_fd *fd, int pin, int set);
#define fd_gpio_set(fd, pin) fd_gpio_set_clr((fd), (pin), 1)
#define fd_gpio_clr(fd, pin) fd_gpio_set_clr((fd), (pin), 0)
/* Functions exported by time.c */
extern int fd_time_init(struct spec_fd *fd);
extern void fd_time_exit(struct spec_fd *fd);
extern int fd_time_set(struct spec_fd *fd, struct fd_time *t,
struct timespec *ts);
extern int fd_time_get(struct spec_fd *fd, struct fd_time *t,
struct timespec *ts);
/* Functions exported by fd-zio.c */
extern int fd_zio_register(void);
extern void fd_zio_unregister(void);
......
/*
* SPI access to fine-delay internals
*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2 as published by the Free Software Foundation or, at your
* option, any later version.
*/
#include <linux/io.h>
#include <linux/time.h>
#include <linux/spinlock.h>
#include "fine-delay.h"
#include "hw/fd_main_regs.h"
/* If fd_time is not null, use it. if ts is not null, use it, else current */
int fd_time_set(struct spec_fd *fd, struct fd_time *t, struct timespec *ts)
{
uint32_t tcr;
unsigned long flags;
struct timespec localts;
spin_lock_irqsave(&fd->lock, flags);
fd_writel(fd, 0, FD_REG_GCR);
if (t) {
fd_writel(fd, t->utc >> 32, FD_REG_TM_SECH);
fd_writel(fd, t->utc & 0xffffffff, FD_REG_TM_SECL);
fd_writel(fd, t->coarse, FD_REG_TM_CYCLES);
} else {
if (!ts) {
/* no caller-provided time: use Linux timer */
ts = &localts;
getnstimeofday(ts);
}
if (BITS_PER_LONG > 32)
fd_writel(fd, ts->tv_sec >> 32, FD_REG_TM_SECH);
else
fd_writel(fd, 0, FD_REG_TM_SECH);
fd_writel(fd, (int32_t)ts->tv_sec, FD_REG_TM_SECL);
fd_writel(fd, ts->tv_nsec >> 3, FD_REG_TM_CYCLES);
}
tcr = fd_readl(fd, FD_REG_TCR);
fd_writel(fd, tcr | FD_TCR_SET_TIME, FD_REG_TCR);
spin_unlock_irqrestore(&fd->lock, flags);
return 0;
}
/* If fd_time is not null, use it. Otherwise use ts */
int fd_time_get(struct spec_fd *fd, struct fd_time *t, struct timespec *ts)
{
uint32_t h1, l1, h2, l2, c;
unsigned long flags;
spin_lock_irqsave(&fd->lock, flags);
/* get the tuple. If inconsistent re-read the high part */
h1 = fd_readl(fd, FD_REG_TM_SECH);
l1 = fd_readl(fd, FD_REG_TM_SECL);
c = fd_readl(fd, FD_REG_TM_CYCLES);
h2 = fd_readl(fd, FD_REG_TM_SECH);
l2 = fd_readl(fd, FD_REG_TM_SECL);
if (h2 != h1 || l2 != l1) {
c = fd_readl(fd, FD_REG_TM_CYCLES);
h1 = h2;
l1 = l2;
}
spin_unlock_irqrestore(&fd->lock, flags);
printk("got %i %i %i\n", h1, l1, c);
if (t) {
t->utc = ((uint64_t)h1 << 32) | l1;
t->coarse = c;
}
if (ts) {
ts->tv_sec = ((uint64_t)h1 << 32) | l1;
ts->tv_nsec = c * 8;
}
return 0;
}
int fd_time_init(struct spec_fd *fd)
{
/* nothing to do */
return 0;
}
void fd_time_exit(struct spec_fd *fd)
{
/* nothing to do */
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment