Skip to content
Snippets Groups Projects
fmc-trivial.c 1.59 KiB
Newer Older
/* A trivial fmc driver that can load a gateware file and reports interrupts */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/firmware.h>
#include <linux/fmc.h>
#include "spec.h"

static char *t_filename;
module_param_named(file, t_filename, charp, 0444);

irqreturn_t t_handler(int irq, void *dev_id)
{
	struct fmc_device *fmc = dev_id;

	fmc->op->irq_ack(fmc);
	printk("%s: irq %i\n", __func__, irq);
	return IRQ_HANDLED;
}

int t_probe(struct fmc_device *fmc)
{
	int ret;
	struct device *dev = fmc->hwdev;
	ret = fmc->op->irq_request(fmc, t_handler, "fmc-trivial", 0);
	if (ret < 0)
		return ret;

	if (t_filename) {
		const struct firmware *fw;

		ret = request_firmware(&fw, t_filename, dev);
		if (ret < 0) {
			dev_warn(dev, "request firmware \"%s\": error %i\n",
				t_filename, ret);
			ret = 0; /* not fatal */
		} else {
			ret = fmc->op->reprogram(fmc, (void *)fw->data,
						 fw->size);
		}
		if (ret <0) {
			dev_err(dev, "write firmware \"%s\": error %i\n",
				t_filename, ret);
			ret = 0; /* not fatal, either (lazy me) */
		}
	}
	return ret;
}

int t_remove(struct fmc_device *fmc)
{
	fmc->op->irq_free(fmc);
	return 0;
}

static struct fmc_driver t_drv = {
	.driver.name = KBUILD_MODNAME,
	.probe = t_probe,
	.remove = t_remove,
	/* no table, as the current match just matches everything */
};

static int t_init(void)
{
	int ret;

	ret = fmc_driver_register(&t_drv);
	return ret;
}

static void t_exit(void)
{
	fmc_driver_unregister(&t_drv);
}

module_init(t_init);
module_exit(t_exit);

MODULE_LICENSE("GPL and additional rights"); /* public domain */