X-Git-Url: http://rtime.felk.cvut.cz/gitweb/shark/motorek-5200.git/blobdiff_plain/4600cc7bd042e0a04eec6e293968cd37641d8543..HEAD:/motorek.c diff --git a/motorek.c b/motorek.c index 205297f..1ab1bf8 100644 --- a/motorek.c +++ b/motorek.c @@ -1,16 +1,33 @@ +/* + * Driver for DC motor connected to MPC5200 based boards. + * + * The motor is used for education at Czech Technical University + * in Prague. + * + * Authors: + * Michal Sojka + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + #include #include #include #include #include -#include +#include #include +#include struct motorek { - struct mpc52xx_gpt *pwmf, *pwmb; + struct mpc52xx_gpt *pwmf, *pwmb, *irca, *ircb; atomic_t pos; int irq; int action; + int last_irc_state; }; static ssize_t show_position(struct device *dev, @@ -55,7 +72,13 @@ DEVICE_ATTR(action,0644,show_action,store_action); #define MPC52xx_GPT_MODE_PWM 3 #define MPC52xx_GPT_MODE_GPIO 4 -#define MPC52xx_GPT_PWM_OP (1<<8) +#define MPC52xx_GPT_MODE_GPIO_IN (0<<4) +#define MPC52xx_GPT_MODE_GPIO_OUT0 (2<<4) +#define MPC52xx_GPT_MODE_GPIO_OUT1 (1<<4) + +#define MPC52xx_GPT_STATUS_PIN (1<<8) + +#define MPC52xx_GPT_PWM_OP (1<<8) /* PWM polarity */ /* Base clock 132 MHz * (/proc/device-tree/cpus/PowerPC,5200@0/bus-frequency) */ @@ -69,7 +92,7 @@ static void pwm_width(struct mpc52xx_gpt *gpt, u16 width) } -static void __devinit pwm_init(struct mpc52xx_gpt *gpt) +static void __devinit init_pwn(struct mpc52xx_gpt *gpt) { //while (((unsigned)gpt & 0xff) != 0x50) gpt++; out_be32(&gpt->count, (1<<16) | PWM_PERIOD); @@ -82,6 +105,13 @@ static void __devinit pwm_init(struct mpc52xx_gpt *gpt) //printk("pwm: %p\n", gpt); } +static void __devinit init_input(struct mpc52xx_gpt *gpt) +{ + out_be32(&gpt->mode, + MPC52xx_GPT_MODE_GPIO | + MPC52xx_GPT_MODE_GPIO_IN); +} + static void pwm_done(struct mpc52xx_gpt *gpt) { out_be32(&gpt->mode, 0); @@ -103,9 +133,10 @@ static void motorek_action(struct motorek *m, int action_permile) static int __devinit motorek_init(struct motorek *m) { - pwm_init(m->pwmf); - pwm_init(m->pwmb); - //motorek_action(m, +0); + init_pwn(m->pwmf); + init_pwn(m->pwmb); + init_input(m->irca); + init_input(m->ircb); return 0; } @@ -115,34 +146,64 @@ static int motorek_done(struct motorek *m) pwm_done(m->pwmb); return 0; } +#define TRANSITION(old, new) (((old) << 2) | new) +static const int table[16] = { + [TRANSITION(0,1)] = +1, + [TRANSITION(1,3)] = +1, + [TRANSITION(3,2)] = +1, + [TRANSITION(2,0)] = +1, + + [TRANSITION(1,0)] = -1, + [TRANSITION(3,1)] = -1, + [TRANSITION(2,3)] = -1, + [TRANSITION(0,2)] = -1, +}; static irqreturn_t motorek_irq(int irq, void *dev_id) { struct motorek *m = dev_id; - atomic_inc(&m->pos); + int irc_state = + ((in_be32(&m->irca->status) & MPC52xx_GPT_STATUS_PIN) ? 1 : 0) | \ + ((in_be32(&m->ircb->status) & MPC52xx_GPT_STATUS_PIN) ? 2 : 0); + atomic_add(table[TRANSITION(m->last_irc_state, irc_state)], &m->pos); + m->last_irc_state = irc_state; return IRQ_HANDLED; } -struct mpc52xx_gpt __iomem *iomap_gpt_by_phandle(const phandle *phandle) +static struct of_device_id mpc5200_gpt_match[] = { + { .compatible = "mpc5200-gpt", }, + { .compatible = "fsl,mpc5200-gpt", }, + {}, +}; + +struct mpc52xx_gpt __iomem *iomap_gpt_by_phandle_prop(struct device_node *dn, const char *prop) { struct device_node *np; - struct mpc52xx_gpt __iomem *gpt; + struct mpc52xx_gpt __iomem *gpt = NULL; + const phandle *phandle; + phandle = of_get_property(dn, prop, NULL); if (!phandle) return NULL; np = of_find_node_by_phandle(*phandle); if (!np) return NULL; + + if (!of_match_node(mpc5200_gpt_match, np)) { + printk(KERN_ERR "property %s doesn't refer to GPT\n", prop); + goto out; + } + gpt = of_iomap(np, 0); +out: of_node_put(np); return gpt; } -static int __devinit motorek_probe(struct of_device* dev, - const struct of_device_id *match) +static int __devinit motorek_probe(struct platform_device* dev) { - struct device_node *dn = dev->node; + struct device_node *dn = dev->dev.of_node; struct motorek *m; int err; @@ -150,46 +211,66 @@ static int __devinit motorek_probe(struct of_device* dev, if (!m) return -ENOMEM; - m->pwmf = iomap_gpt_by_phandle(of_get_property(dn, "pwmf", NULL)); - m->pwmb = iomap_gpt_by_phandle(of_get_property(dn, "pwmb", NULL)); - - if (!m->pwmf || !m->pwmb) { - printk(KERN_ERR "%s() mmap failed\n", __func__); - return -ENXIO; - } + err = -ENODEV; + + m->pwmf = iomap_gpt_by_phandle_prop(dn, "pwmf"); + if (!m->pwmf) + goto err_free; + m->pwmb = iomap_gpt_by_phandle_prop(dn, "pwmb"); + if (!m->pwmb) + goto err_unmap_pf; + m->irca = iomap_gpt_by_phandle_prop(dn, "irca"); + if (!m->irca) + goto err_unmap_pb; + m->ircb = iomap_gpt_by_phandle_prop(dn, "ircb"); + if (!m->ircb) + goto err_unmap_ia; m->irq = irq_of_parse_and_map(dn, 0); - + if (m->irq == NO_IRQ) + goto err_unmap_ib; err = request_irq(m->irq, motorek_irq, 0, "motorek", m); if (err) - return err; + goto err_unmap_ib; motorek_init(m); platform_set_drvdata(dev, m); - err = device_create_file(&dev->dev,&dev_attr_position); if (err) - return err; + goto err_irq; err = device_create_file(&dev->dev,&dev_attr_action); if (err) - return err; + goto err_irq; printk(KERN_NOTICE "Motorek initialized\n"); return 0; + +err_irq: + free_irq(m->irq, m); +err_unmap_ib: + iounmap(m->pwmb); +err_unmap_ia: + iounmap(m->pwmf); +err_unmap_pb: + iounmap(m->pwmb); +err_unmap_pf: + iounmap(m->pwmf); +err_free: + kfree(m); + return err; } -static int __devexit motorek_remove(struct of_device* dev) +static int __devexit motorek_remove(struct platform_device* dev) { struct motorek *m; - m = platform_get_drvdata(dev); printk(KERN_NOTICE "Removing motorek\n"); - + m = platform_get_drvdata(dev); free_irq(m->irq, m); - motorek_done(m); + kfree(m); return 0; } @@ -197,19 +278,21 @@ static struct of_device_id motorek_match[] = { { .type = "motorek", }, {}, }; -static struct of_platform_driver motorek_driver = { - .owner = THIS_MODULE, - .name = "motorek", - .match_table = motorek_match, +static struct platform_driver motorek_driver = { .probe = motorek_probe, .remove = __devexit_p(motorek_remove), + .driver = { + .name = "motorek", + .owner = THIS_MODULE, + .of_match_table = motorek_match, + }, }; static int __init motorek_init_module(void) { int ret; - struct of_device *dev; + struct platform_device *dev; struct device_node *dn; for_each_node_by_type(dn, "motorek") { @@ -220,14 +303,13 @@ static int __init motorek_init_module(void) } }; - ret = of_register_platform_driver(&motorek_driver); + ret = platform_driver_register(&motorek_driver); return ret; } -module_init(motorek_init_module); static void __exit motorek_exit_module(void) { - struct of_device *dev; + struct platform_device *dev; struct device_node *dn; for_each_node_by_type(dn, "motorek") { @@ -235,8 +317,10 @@ static void __exit motorek_exit_module(void) of_device_unregister(dev); } } - of_unregister_platform_driver(&motorek_driver); + platform_driver_unregister(&motorek_driver); } + +module_init(motorek_init_module); module_exit(motorek_exit_module);