Commit fcddc1cd authored by Alessandro Rubini's avatar Alessandro Rubini

port to fmc-bus abstraction

Several changes to make it compile under the new abstraction

- probe and remove are related to an fmc_driver structure. Thus
the fd-spec.c is obsolete.  Still, the driver is bound to the spec
and as such it refuses to initialize under a different carrier.

- we don't have "spec" in the structure but "fmc"

- i2c referred to pdev, but has been cleaned up

- fd-zio unfortunately refers to pdev to build the local ID.

Still a lot of details are to be fixed.
Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent 415d3789
......@@ -14,7 +14,7 @@ subdirs-ccflags-y = $(ccflags-y)
obj-m := spec-fine-delay.o
spec-fine-delay-objs = fd-zio.o fd-spec.o fd-core.o
spec-fine-delay-objs = fd-zio.o fd-core.o
spec-fine-delay-objs += onewire.o spi.o i2c.o gpio.o
spec-fine-delay-objs += acam.o calibrate.o pll.o time.o
......
......@@ -26,12 +26,13 @@
#include "hw/fd_main_regs.h"
/* Module parameters */
static int fd_regs_offset = FD_REGS_OFFSET;
module_param_named(regs, fd_regs_offset, int, 0444);
static int fd_verbose = 0;
module_param_named(verbose, fd_verbose, int, 0444);
static struct fmc_driver fd_drv; /* forward declaration */
FMC_PARAM_BUSID(fd_drv);
FMC_PARAM_GATEWARE(fd_drv);
/* This is pre-set at load time (data by Tomasz) */
static struct fd_calib fd_default_calib = {
.frr_poly = {
......@@ -128,37 +129,66 @@ static struct fd_modlist mods[] = {
SUBSYS(zio),
};
/* probe and remove are called by fd-spec.c */
int fd_probe(struct spec_dev *dev)
/* probe and remove are called by the FMC bus core */
int fd_probe(struct fmc_device *fmc)
{
struct fd_modlist *m;
struct spec_fd *fd;
int i, ret;
struct spec_dev *spec;
char *fwname;
int i, index, ret;
fd = kzalloc(sizeof(*fd), GFP_KERNEL);
if (!fd) {
pr_err("%s: can't allocate device\n", __func__);
dev_err(fmc->hwdev, "can't allocate device\n");
return -ENOMEM;
}
if (strcmp (fmc->carrier_name, "SPEC")) {
dev_err(fmc->hwdev, "driver \"%s\" only works on SPEC card\n",
KBUILD_MODNAME);
dev_err(fmc->hwdev, "support for carrier \"%s\" is missing\n",
fmc->carrier_name);
return -ENODEV;
}
index = fmc->op->validate(fmc, &fd_drv);
if (index < 0) {
dev_info(fmc->hwdev, "not using \"%s\" according to "
"modparam\n", KBUILD_MODNAME);
return -ENODEV;
}
fwname = FDELAY_GATEWARE_NAME;
if (fd_drv.gw_n)
fwname = ""; /* ->reprogram will pick from module parameter */
ret = fmc->op->reprogram(fmc, &fd_drv, fwname);
if (ret < 0) {
if (ret == -ESRCH) {
dev_info(fmc->hwdev, "%s: no gateware at index %i\n",
KBUILD_MODNAME, index);
return -ENODEV;
}
return ret; /* other error: pass over */
}
spec = fmc->carrier_data;
spin_lock_init(&fd->lock);
dev->sub_priv = fd;
fd->spec = dev;
fd->base = dev->remap[0];
fd->regs = fd->base + fd_regs_offset;
fmc->mezzanine_data = fd;
fd->fmc = fmc;
/* FIXME: don't use base below, but fmc_readl/fmc_writel */
fd->regs = fmc->base + 0x80000; /* FIXME: check this 80000 */
fd->ow_regs = fd->regs + 0x500;
fd->verbose = fd_verbose;
fd->calib = fd_default_calib;
/* Check the binary is there */
if (fd_readl(fd, FD_REG_IDR) != FD_MAGIC_FPGA) {
pr_err("%s: card at %04x:%04x (regs @ 0x%x): wrong gateware\n",
__func__, dev->pdev->bus->number, dev->pdev->devfn,
fd_regs_offset);
dev_err(fmc->hwdev, "wrong gateware\n");
return -ENODEV;
} else {
pr_info("%s: card at %04x:%04x (regs @ 0x%x): initializing\n",
__func__, dev->pdev->bus->number, dev->pdev->devfn,
fd_regs_offset);
dev_info(fmc->hwdev, "%s: initializing\n", KBUILD_MODNAME);
}
/* First, hardware reset */
......@@ -202,22 +232,30 @@ err:
return ret;
}
void fd_remove(struct spec_dev *dev)
int fd_remove(struct fmc_device *fmc)
{
struct fd_modlist *m;
struct spec_fd *fd = dev->sub_priv;
struct spec_fd *fd = fmc->mezzanine_data;
int i = ARRAY_SIZE(mods);
if (!test_bit(FD_FLAG_INITED, &fd->flags))
return; /* No init, no exit */
if (!test_bit(FD_FLAG_INITED, &fd->flags)) /* FIXME: ditch this */
return 0; /* No init, no exit */
while (--i >= 0) {
m = mods + i;
if (m->exit)
m->exit(fd);
}
return 0;
}
static struct fmc_driver fd_drv = {
.driver.name = KBUILD_MODNAME,
.probe = fd_probe,
.remove = fd_remove,
/* no table, as the current match just matches everything */
};
static int fd_init(void)
{
int ret;
......@@ -225,7 +263,7 @@ static int fd_init(void)
ret = fd_zio_register();
if (ret < 0)
return ret;
ret = fd_spec_init();
ret = fmc_driver_register(&fd_drv);
if (ret < 0) {
fd_zio_unregister();
return ret;
......@@ -235,7 +273,7 @@ static int fd_init(void)
static void fd_exit(void)
{
fd_spec_exit();
fmc_driver_unregister(&fd_drv);
fd_zio_unregister();
}
......
/*
* SPEC interface for the fine-delay driver
*
* Copyright (C) 2012 CERN (www.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/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/io.h>
#include "spec.h"
#include "fine-delay.h"
static int fd_is_valid(int bus, int devfn)
{
/* FIXME: restrict to some of the spec devices with moduleparam */
return 1;
}
int fd_spec_init(void)
{
struct spec_dev *dev;
int ret, success = 0, retsave = 0, err = 0;
/* Scan the list and see what is there. Take hold of everything */
list_for_each_entry(dev, &spec_list, list) {
if (!fd_is_valid(dev->pdev->bus->number, dev->pdev->devfn))
continue;
pr_debug("%s: init %04x:%04x (%pR - %p)\n", __func__,
dev->pdev->bus->number, dev->pdev->devfn,
dev->area[0], dev->remap[0]);
ret = fd_probe(dev);
if (ret < 0) {
retsave = ret;
err++;
} else {
success++;
}
}
if (err) {
pr_err("%s: Setup of %i boards failed (%i succeeded)\n",
KBUILD_MODNAME, err, success);
pr_err("%s: last error: %i\n", KBUILD_MODNAME, retsave);
}
if (success) {
/* At least one board has been successfully initialized */
return 0;
}
return retsave; /* last error code */
}
void fd_spec_exit(void)
{
struct spec_dev *dev;
list_for_each_entry(dev, &spec_list, list) {
if (!fd_is_valid(dev->pdev->bus->number, dev->pdev->devfn))
continue;
pr_debug("%s: release %04x:%04x (%pR - %p)\n", __func__,
dev->pdev->bus->number, dev->pdev->devfn,
dev->area[0], dev->remap[0]);
fd_remove(dev);
}
}
......@@ -802,6 +802,7 @@ void fd_zio_unregister(void)
int fd_zio_init(struct spec_fd *fd)
{
int err = 0;
struct spec_dev *spec;
struct pci_dev *pdev;
int dev_id;
......@@ -814,7 +815,8 @@ int fd_zio_init(struct spec_fd *fd)
fd->hwzdev->priv_d = fd;
/* Our dev_id is bus+devfn */
pdev = fd->spec->pdev;
spec = fd->fmc->carrier_data;
pdev = spec->pdev;
dev_id = (pdev->bus->number << 8) | pdev->devfn;
err = zio_register_device(fd->hwzdev, "fd", dev_id);
......
#ifndef __FINE_DELAY_H__
#define __FINE_DELAY_H__
#define FDELAY_VERSION 2
#define FDELAY_GATEWARE_NAME "fmc/fine-delay.bin"
#define FDELAY_VERSION 2 /* version of the layout of registers */
/*
* ZIO concatenates device, cset and channel extended attributes in the 32
* values that are reported in the control block. So we are limited to
......@@ -153,7 +155,7 @@ struct fd_ch {
struct spec_fd {
spinlock_t lock;
unsigned long flags;
struct spec_dev *spec;
struct fmc_device *fmc;
struct zio_device *zdev, *hwzdev;
struct timer_list fifo_timer;
struct timer_list temp_timer;
......@@ -285,10 +287,6 @@ static inline void __check_output(int x)
#define FD_GPIO_TRIG_INTERNAL 0x0040 /* TDC trig (1=in, 1=fpga) */
#define FD_GPIO_CAL_DISABLE 0x0080 /* 0 enables calibration */
/* Functions exported by fd-core.c */
extern int fd_probe(struct spec_dev *dev);
extern void fd_remove(struct spec_dev *dev);
/* Functions exported by spi.c */
extern int fd_spi_xfer(struct spec_fd *fd, int ss, int num_bits,
uint32_t in, uint32_t *out);
......
......@@ -218,39 +218,25 @@ static void fd_i2c_load_calib(struct spec_fd *fd,
struct fd_calib_on_eeprom *cal_ee)
{
const struct firmware *fw;
struct pci_dev *pdev = fd->spec->pdev;
char *fwname, *newname = NULL;
int err;
/* the calibration_load string is known to be valid */
fwname = calibration_load;
err = request_firmware(&fw, calibration_load, &pdev->dev);
err = request_firmware(&fw, calibration_load, fd->fmc->hwdev);
if (err < 0) {
dev_warn(&pdev->dev, "can't load \"%s\"\n",
dev_warn(fd->fmc->hwdev, "can't load \"%s\"\n",
calibration_load);
newname = kasprintf(GFP_KERNEL, "%s-%02x%02x\n",
calibration_load,
pdev->bus->number, pdev->devfn);
err = request_firmware(&fw, newname, &pdev->dev);
if (err < 0) {
dev_warn(&pdev->dev, "can't load \"%s\"\n",
newname);
}
fwname = newname;
}
if (err < 0) {
kfree(newname);
return;
}
if (fw->size != sizeof(cal_ee->calib)) {
dev_warn(&pdev->dev, "File \"%s\" has wrong size\n",
dev_warn(fd->fmc->hwdev, "File \"%s\" has wrong size\n",
fwname);
} else {
memcpy(&cal_ee->calib, fw->data, fw->size);
dev_info(&pdev->dev, "calibration data loaded from \"%s\"\n",
fwname);
dev_info(fd->fmc->hwdev,
"calibration data loaded from \"%s\"\n", fwname);
}
release_firmware(fw);
kfree(newname);
......
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