]> rtime.felk.cvut.cz Git - shark/motorek-5200.git/blob - motorek.c
Adde messages, converte to oout_be32()
[shark/motorek-5200.git] / motorek.c
1 #include <linux/module.h>
2 #include <linux/platform_device.h>
3 #include <linux/mod_devicetable.h>
4 #include <linux/of.h>
5 #include <asm-powerpc/mpc52xx.h>
6 #include <linux/interrupt.h>
7
8 struct motorek {
9         struct mpc52xx_gpt *pwmf, *pwmb;
10         atomic_t pos;
11         int irq;
12 };
13
14 static ssize_t show_position(struct device *dev,
15                             struct device_attribute *attr, char *buf)
16 {
17         struct platform_device  *pdev = to_platform_device(dev);
18         struct motorek          *m = platform_get_drvdata(pdev);
19
20         int len = snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&m->pos));
21         return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
22 }
23
24 DEVICE_ATTR(position,0444,show_position,NULL);
25
26 #define MPC52xx_GPT_MODE_DISABLED 0
27 #define MPC52xx_GPT_MODE_INCAPT   1
28 #define MPC52xx_GPT_MODE_OUTCMP   2
29 #define MPC52xx_GPT_MODE_PWM      3
30 #define MPC52xx_GPT_MODE_GPIO     4
31
32 #define MPC52xx_GPT_PWM_OP        (1<<8)
33
34 /* Base clock 132 MHz
35  * (/proc/device-tree/cpus/PowerPC,5200@0/bus-frequency) */
36 #define PWM_PERIOD 6600         /* = 132 000 kHz / 20 kHz  */
37
38
39 static void pwm_width(struct mpc52xx_gpt *gpt, u16 width)
40 {
41         out_be32(&gpt->pwm, (width<<16) | MPC52xx_GPT_PWM_OP);
42 }
43
44 static void __devinit pwm_init(struct mpc52xx_gpt *gpt)
45 {
46         out_be32(&gpt->count, (1<<16) | PWM_PERIOD);
47         pwm_width(gpt, 0);
48         out_be32(&gpt->mode, MPC52xx_GPT_MODE_PWM);
49 }
50
51 static void  pwm_done(struct mpc52xx_gpt *gpt)
52 {
53         out_be32(&gpt->mode, 0);
54         out_be32(&gpt->count, 0);
55         pwm_width(gpt, 0);
56 }
57
58 static void motorek_action(struct motorek *m, int action_permile)
59 {
60         if (action_permile >= 0) {
61                 pwm_width(m->pwmb, 0);
62                 pwm_width(m->pwmf, +action_permile*PWM_PERIOD/1000);
63         } else {
64                 pwm_width(m->pwmf, 0);
65                 pwm_width(m->pwmb, -action_permile*PWM_PERIOD/1000);
66         }
67 }
68
69 static int __devinit motorek_init(struct motorek *m)
70 {
71         pwm_init(m->pwmf);
72         pwm_init(m->pwmb);
73 /*      motorek_action(m, +45); */
74         pwm_width(m->pwmb, 500);
75         pwm_width(m->pwmf, 500);
76         return 0;
77 }
78
79 static int motorek_done(struct motorek *m)
80 {
81         pwm_done(m->pwmf);
82         pwm_done(m->pwmb);
83         return 0;
84 }
85
86 static irqreturn_t motorek_irq(int irq, void *dev_id)
87 {
88         struct motorek *m = dev_id;
89         atomic_inc(&m->pos);
90         return IRQ_HANDLED;
91 }
92
93 /* mpc5200 device tree match tables */
94 static struct of_device_id mpc5200_gpt_ids[] __initdata = {
95         { .compatible = "fsl,mpc5200-gpt", },
96         { .compatible = "mpc5200-gpt", },
97         {}
98 };
99
100 static int __devinit motorek_probe(struct platform_device *dev)
101 {
102         struct device_node *np;
103         struct motorek *m;
104         int err;
105
106         m = kzalloc(sizeof(*m), GFP_KERNEL);
107         if (!m)
108                 return -ENOMEM;
109
110         for_each_matching_node(np, mpc5200_gpt_ids) {
111                 const void *prop;
112                 int i;
113                 
114                 prop = of_get_property(np, "cell-index", NULL);
115                 if (prop) {
116                         i = *(u32 *)prop;
117                         switch (i) {
118                         case 1:
119                                 m->pwmf = of_iomap(np, 0);
120                                 break;
121                         case 2:
122                                 m->pwmb = of_iomap(np, 0);
123                                 break;
124                         }
125                 }
126         }
127         if (!m->pwmf || !m->pwmb) {
128                 printk(KERN_ERR "%s() mmap failed\n", __func__);
129                 return -ENXIO;
130         }
131
132 /*      /\* FIXME: This should be specified in device-tree *\/ */
133 /*      m->irq = irq_create_of_mapping( */
134
135 /*      err = request_irq(m->irq, motorek_irq, 0, "motorek", m); */
136 /*      if (err) */
137 /*              return err; */
138
139         motorek_init(m);
140
141         platform_set_drvdata(dev, m);
142
143         err = device_create_file(&dev->dev,&dev_attr_position);
144         if (err)
145                 return err;
146
147         printk(KERN_NOTICE "Motorek initialized\n");
148
149         return 0;
150 }
151
152 static int __devexit motorek_remove(struct platform_device *dev)
153 {
154         struct motorek *m;
155         m = platform_get_drvdata(dev);
156
157         printk(KERN_NOTICE "Removing motorek\n");
158
159         motorek_done(m);
160         return 0;
161 }
162
163
164
165 static struct platform_driver motorek_driver = {
166         .probe          = motorek_probe,
167         .remove         = __devexit_p(motorek_remove),
168         .driver         = {
169                 .name   = "motorek",
170                 .owner  = THIS_MODULE,
171         },
172 };
173
174
175 static struct platform_device *motorek_pdev;
176
177 static int __init motorek_init_module(void)
178 {
179         int ret;
180         motorek_pdev = platform_device_alloc("motorek", 0);
181         if (!motorek_pdev)
182                 return -ENOMEM;
183         ret = platform_device_add(motorek_pdev);
184         if (ret) {
185                 platform_device_put(motorek_pdev);
186                 return ret;
187         }
188
189         ret = platform_driver_register(&motorek_driver);
190         return 0;
191 }
192 module_init(motorek_init_module);
193
194 static void __exit motorek_exit_module(void)
195 {
196         platform_device_unregister(motorek_pdev);
197         platform_driver_unregister(&motorek_driver);
198 }
199 module_exit(motorek_exit_module);
200
201
202 MODULE_LICENSE("GPL v2");
203 MODULE_VERSION("0.1");
204 MODULE_AUTHOR("Michal Sojka <sojkam1@fel.cvut.cz>");