From 7817bdd9f3648065911c91400f754f9058757120 Mon Sep 17 00:00:00 2001 From: Michal Sojka Date: Thu, 15 Jan 2009 10:05:49 +0100 Subject: [PATCH] Initial commit Onw PWM is working --- Makefile | 13 ++++ motorek.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 211 insertions(+) create mode 100644 Makefile create mode 100644 motorek.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7ba6fa2 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +ifneq ($(KERNELRELEASE),) +# kbuild part of makefile +obj-m := motorek.o + +else +# Normal Makefile + +KERNELDIR := /lib/modules/`uname -r`/build +all:: + $(MAKE) -C $(KERNELDIR) M=`pwd` $@ + +endif + diff --git a/motorek.c b/motorek.c new file mode 100644 index 0000000..98a2db1 --- /dev/null +++ b/motorek.c @@ -0,0 +1,198 @@ +#include +#include +#include +#include +#include +#include + +struct motorek { + struct mpc52xx_gpt *pwmf, *pwmb; + atomic_t pos; + int irq; +}; + +static ssize_t show_position(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct motorek *m = platform_get_drvdata(pdev); + + int len = snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&m->pos)); + return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; +} + +DEVICE_ATTR(position,0444,show_position,NULL); + +#define MPC52xx_GPT_MODE_DISABLED 0 +#define MPC52xx_GPT_MODE_INCAPT 1 +#define MPC52xx_GPT_MODE_OUTCMP 2 +#define MPC52xx_GPT_MODE_PWM 3 +#define MPC52xx_GPT_MODE_GPIO 4 + +#define MPC52xx_GPT_PWM_OP (1<<8) + +/* Base clock 132 MHz + * (/proc/device-tree/cpus/PowerPC,5200@0/bus-frequency) */ +#define PWM_PERIOD 6600 /* = 132 000 kHz / 20 kHz */ + + +static void pwm_width(struct mpc52xx_gpt *gpt, u16 width) +{ + gpt->pwm = (width<<16) | MPC52xx_GPT_PWM_OP; +} + +static void __devinit pwm_init(struct mpc52xx_gpt *gpt) +{ + gpt->count = (1<<16) | PWM_PERIOD; + pwm_width(gpt, 0); + gpt->mode = MPC52xx_GPT_MODE_PWM; +} + +static void pwm_done(struct mpc52xx_gpt *gpt) +{ + gpt->mode = 0; + gpt->count = 0; + pwm_width(gpt, 0); +} + +static void motorek_action(struct motorek *m, int action_permile) +{ + if (action_permile >= 0) { + pwm_width(m->pwmb, 0); + pwm_width(m->pwmf, +action_permile*PWM_PERIOD/1000); + } else { + pwm_width(m->pwmf, 0); + pwm_width(m->pwmb, -action_permile*PWM_PERIOD/1000); + } +} + +static int __devinit motorek_init(struct motorek *m) +{ + pwm_init(m->pwmf); + pwm_init(m->pwmb); + motorek_action(m, +45); + return 0; +} + +static int motorek_done(struct motorek *m) +{ + pwm_done(m->pwmf); + pwm_done(m->pwmb); + return 0; +} + +static irqreturn_t motorek_irq(int irq, void *dev_id) +{ + struct motorek *m = dev_id; + atomic_inc(&m->pos); + return IRQ_HANDLED; +} + +/* mpc5200 device tree match tables */ +static struct of_device_id mpc5200_gpt_ids[] __initdata = { + { .compatible = "fsl,mpc5200-gpt", }, + { .compatible = "mpc5200-gpt", }, + {} +}; + +static int __devinit motorek_probe(struct platform_device *dev) +{ + struct device_node *np; + struct motorek *m; + int err; + + m = kzalloc(sizeof(*m), GFP_KERNEL); + if (!m) + return -ENOMEM; + + for_each_matching_node(np, mpc5200_gpt_ids) { + const void *prop; + int i; + + prop = of_get_property(np, "cell-index", NULL); + if (prop) { + i = *(u32 *)prop; + switch (i) { + case 1: + m->pwmf = of_iomap(np, 0); + break; + case 2: + m->pwmb = of_iomap(np, 0); + break; + } + } + } + if (!m->pwmf || !m->pwmb) { + printk(KERN_ERR "%s() mmap failed\n", __func__); + return -ENXIO; + } + +/* /\* FIXME: This should be specified in device-tree *\/ */ +/* m->irq = irq_create_of_mapping( */ + +/* err = request_irq(m->irq, motorek_irq, 0, "motorek", m); */ +/* if (err) */ +/* return err; */ + + motorek_init(m); + + platform_set_drvdata(dev, m); + + err = device_create_file(&dev->dev,&dev_attr_position); + if (err) + return err; + + return 0; +} + +static int __devexit motorek_remove(struct platform_device *dev) +{ + struct motorek *m; + m = platform_get_drvdata(dev); + + motorek_done(m); + return 0; +} + + + +static struct platform_driver motorek_driver = { + .probe = motorek_probe, + .remove = __devexit_p(motorek_remove), + .driver = { + .name = "motorek", + .owner = THIS_MODULE, + }, +}; + + +static struct platform_device *motorek_pdev; + +static int __init motorek_init_module(void) +{ + int ret; + motorek_pdev = platform_device_alloc("motorek", 0); + if (!motorek_pdev) + return -ENOMEM; + ret = platform_device_add(motorek_pdev); + if (ret) { + platform_device_put(motorek_pdev); + return ret; + } + + ret = platform_driver_register(&motorek_driver); + return 0; +} +module_init(motorek_init_module); + +static void __exit motorek_exit_module(void) +{ + platform_device_unregister(motorek_pdev); + platform_driver_unregister(&motorek_driver); +} +module_exit(motorek_exit_module); + + +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("0.1"); +MODULE_AUTHOR("Michal Sojka "); -- 2.39.2