Commit 689c5997 authored by Federico Vaga's avatar Federico Vaga

sw:drv: can't use MFD, we need to be able to set dma_mask

Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent df8a653d
......@@ -4,6 +4,8 @@
* Author: Federico Vaga <federico.vaga@cern.ch>
*/
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
......@@ -12,6 +14,8 @@
#include "platform_data/fmc-adc-100m14b4cha.h"
#define SVEC_FMC_SLOTS 2
/*
* From SVEC but we do not want to add a dependency for these 4 registers
* which should never change by design. If they do, and you end up here:
......@@ -24,34 +28,50 @@
#define SVEC_FPGA_CSR_DDR5_DATA (SVEC_BASE_REGS_CSR + 0x24)
enum fa_svec_dev_offsets {
FA_SVEC_ADC1_MEM_START = 0x000002000,
FA_SVEC_ADC1_MEM_END = 0x00003FFF,
FA_SVEC_ADC2_MEM_START = 0x00004000,
FA_SVEC_ADC2_MEM_END = 0x000005FFF,
};
static struct fmc_adc_platform_data fmc_adc_pdata1 = {
.flags = FMC_ADC_BIG_ENDIAN | FMC_ADC_SVEC,
.vme_ddr_offset = SVEC_FPGA_CSR_DDR4_ADDR,
.calib_trig_time = 0,
.calib_trig_threshold = 0,
.calib_trig_internal = 0,
FA_SVEC_ADC1_MEM_START = 0x000002000,
FA_SVEC_ADC1_MEM_END = 0x00003FFF,
FA_SVEC_ADC2_MEM_START = 0x00004000,
FA_SVEC_ADC2_MEM_END = 0x000005FFF,
};
static struct fmc_adc_platform_data fmc_adc_pdata2 = {
.flags = FMC_ADC_BIG_ENDIAN | FMC_ADC_SVEC,
.vme_ddr_offset = SVEC_FPGA_CSR_DDR5_ADDR,
.calib_trig_time = 0,
.calib_trig_threshold = 0,
.calib_trig_internal = 0,
static inline struct platform_device *platform_device_register_resndata_mask(
struct device *parent, const char *name, int id,
const struct resource *res, unsigned int num,
const void *data, size_t size, u64 dma_mask) {
struct platform_device_info pdevinfo = {
.parent = parent,
.name = name,
.id = id,
.res = res,
.num_res = num,
.data = data,
.size_data = size,
.dma_mask = dma_mask,
};
return platform_device_register_full(&pdevinfo);
}
};
/* MFD devices */
enum svec_fpga_mfd_devs_enum {
FA_SVEC_MFD_FA1 = 0,
FA_SVEC_MFD_FA2,
static struct fmc_adc_platform_data fa_svec_adc_pdata[] = {
{
.flags = FMC_ADC_BIG_ENDIAN |
FMC_ADC_SVEC |
FMC_ADC_NOSQUASH_SCATTERLIST,
.vme_ddr_offset = SVEC_FPGA_CSR_DDR4_ADDR,
.calib_trig_time = 0,
.calib_trig_threshold = 0,
.calib_trig_internal = 0,
}, {
.flags = FMC_ADC_BIG_ENDIAN |
FMC_ADC_SVEC |
FMC_ADC_NOSQUASH_SCATTERLIST,
.vme_ddr_offset = SVEC_FPGA_CSR_DDR5_ADDR,
.calib_trig_time = 0,
.calib_trig_threshold = 0,
.calib_trig_internal = 0,
}
};
static struct resource fa_svec_res1[] = {
......@@ -72,6 +92,7 @@ static struct resource fa_svec_res1[] = {
.end = 0,
},
};
static struct resource fa_svec_res2[] = {
{
.name = "fmc-adc-100m-mem.2",
......@@ -91,42 +112,24 @@ static struct resource fa_svec_res2[] = {
},
};
#define MFD_ADC(_n) \
{ \
.name = "fmc-adc-100m", \
.platform_data = &fmc_adc_pdata##_n, \
.pdata_size = sizeof(fmc_adc_pdata##_n), \
.num_resources = ARRAY_SIZE(fa_svec_res##_n), \
.resources = fa_svec_res##_n, \
}
static const struct mfd_cell fa_svec_mfd_devs1[] = {
MFD_ADC(1),
};
static const struct mfd_cell fa_svec_mfd_devs2[] = {
MFD_ADC(2),
};
static const struct mfd_cell fa_svec_mfd_devs3[] = {
MFD_ADC(1),
MFD_ADC(2),
static struct resource *fa_svec_res[] = {
fa_svec_res1,
fa_svec_res2,
};
static const struct mfd_cell *fa_svec_mfd_devs[] = {
fa_svec_mfd_devs1,
fa_svec_mfd_devs2,
fa_svec_mfd_devs3,
struct fa_svec_data {
struct platform_device *adc[2];
};
static int fa_svec_probe(struct platform_device *pdev)
{
struct fa_svec_data *pdev_data;
struct resource *rmem;
int idev = 0;
int ndev;
int irq;
int i;
rmem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
rmem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!rmem) {
dev_err(&pdev->dev, "Missing memory resource\n");
return -EINVAL;
......@@ -138,46 +141,70 @@ static int fa_svec_probe(struct platform_device *pdev)
return -EINVAL;
}
for (i = 1; i <= 2; ++i) {
struct fmc_slot *slot = fmc_slot_get(pdev->dev.parent, i);
pdev_data = kmalloc(sizeof(*pdev_data), GFP_KERNEL);
if (!pdev_data)
return -ENOMEM;
for (i = 0; i < SVEC_FMC_SLOTS; ++i) {
unsigned int res_n = ARRAY_SIZE(fa_svec_res1);
struct resource res[res_n];
struct fmc_slot *slot = fmc_slot_get(pdev->dev.parent, i + 1);
int present;
if (IS_ERR(slot)) {
dev_err(&pdev->dev,
"Can't find FMC slot %d err: %ld\n",
i, PTR_ERR(slot));
return PTR_ERR(slot);
i + 1, PTR_ERR(slot));
continue;
}
present = fmc_slot_present(slot);
fmc_slot_put(slot);
dev_dbg(&pdev->dev, "FMC slot: %d, present: %d\n",
i, present);
if (present)
idev |= BIT(i - 1);
i + 1, present);
if (!present)
continue;
memcpy(res, fa_svec_res[i], sizeof(res));
res[0].parent = rmem;
res[0].start += rmem->start;
res[0].end += rmem->start;
res[2].start += irq;
pdev_data->adc[i] = platform_device_register_resndata_mask(&pdev->dev,
"fmc-adc-100m",
PLATFORM_DEVID_AUTO,
res,
res_n,
&fa_svec_adc_pdata[i],
sizeof(fa_svec_adc_pdata[i]),
DMA_BIT_MASK(32));
if (IS_ERR(pdev_data->adc[i])) {
dev_err(&pdev->dev,
"Faild to register ADC instance %d\n",
i);
pdev_data->adc[i] = NULL;
}
}
if (idev == 0)
return -ENODEV;
idev--;
/*
* We know that this design uses the HTVIC IRQ controller.
* This IRQ controller has a linear mapping, so it is enough
* to give the first one as input
*/
ndev = 1 + !!(idev & 0x2);
dev_dbg(&pdev->dev, "Found %d, point to mfd_cell %d\n", ndev, idev);
return mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO,
fa_svec_mfd_devs[idev], ndev,
rmem, irq, NULL);
platform_set_drvdata(pdev, pdev_data);
return 0;
}
static int fa_svec_remove(struct platform_device *pdev)
{
mfd_remove_devices(&pdev->dev);
struct fa_svec_data *pdev_data = platform_get_drvdata(pdev);
int i;
if (!pdev_data)
return 0;
for (i = 0; i < SVEC_FMC_SLOTS; ++i)
if (pdev_data->adc[i])
platform_device_unregister(pdev_data->adc[i]);
kfree(pdev_data);
return 0;
return 0;
}
/**
......
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