]> rtime.felk.cvut.cz Git - shark/motorek-5200.git/blob - motorek.c
d0633e937a73c962128aac72c55ee3de35898236
[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 <linux/of_platform.h>
6 #include <asm-powerpc/mpc52xx.h>
7 #include <linux/interrupt.h>
8
9 struct motorek {
10         struct mpc52xx_gpt *pwmf, *pwmb, *irca, *ircb;
11         atomic_t pos;
12         int irq;
13         int action;
14         int last_irc_state;
15 };
16
17 static ssize_t show_position(struct device *dev,
18                             struct device_attribute *attr, char *buf)
19 {
20         struct platform_device  *pdev = to_platform_device(dev);
21         struct motorek          *m = platform_get_drvdata(pdev);
22
23         int len = snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&m->pos));
24         return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
25 }
26
27 static ssize_t show_action(struct device *dev,
28                            struct device_attribute *attr, char *buf)
29 {
30         struct platform_device  *pdev = to_platform_device(dev);
31         struct motorek          *m = platform_get_drvdata(pdev);
32
33         int len = snprintf(buf, PAGE_SIZE, "%d\n", m->action);
34         return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
35 }
36
37 static void motorek_action(struct motorek *m, int action_permile);
38 static ssize_t store_action(struct device *dev, struct device_attribute *attr,
39                             const char *buf, size_t count)
40 {
41         struct platform_device  *pdev = to_platform_device(dev);
42         struct motorek          *m = platform_get_drvdata(pdev);
43
44         int a;
45         sscanf(buf, "%d", &a);
46         motorek_action(m, a);
47         return strnlen(buf, PAGE_SIZE);
48 }
49
50 DEVICE_ATTR(position,0444,show_position,NULL);
51 DEVICE_ATTR(action,0644,show_action,store_action);
52
53 #define MPC52xx_GPT_MODE_DISABLED 0
54 #define MPC52xx_GPT_MODE_INCAPT   1
55 #define MPC52xx_GPT_MODE_OUTCMP   2
56 #define MPC52xx_GPT_MODE_PWM      3
57 #define MPC52xx_GPT_MODE_GPIO     4
58
59 #define MPC52xx_GPT_MODE_GPIO_IN   (0<<4)
60 #define MPC52xx_GPT_MODE_GPIO_OUT0 (2<<4)
61 #define MPC52xx_GPT_MODE_GPIO_OUT1 (1<<4)
62
63 #define MPC52xx_GPT_STATUS_PIN (1<<8)
64
65 #define MPC52xx_GPT_PWM_OP        (1<<8) /* PWM polarity */
66
67 /* Base clock 132 MHz
68  * (/proc/device-tree/cpus/PowerPC,5200@0/bus-frequency) */
69 #define PWM_PERIOD 6600         /* = 132 000 kHz / 20 kHz  */
70
71
72 static void pwm_width(struct mpc52xx_gpt *gpt, u16 width)
73 {
74         out_be32(&gpt->pwm, (width<<16) | MPC52xx_GPT_PWM_OP);
75         //printk("pwm: %p=0x%x\n", gpt, width);
76
77 }
78
79 static void __devinit init_pwn(struct mpc52xx_gpt *gpt)
80 {
81         //while (((unsigned)gpt & 0xff) != 0x50) gpt++;
82         out_be32(&gpt->count, (1<<16) | PWM_PERIOD);
83         pwm_width(gpt, 0);
84         out_be32(&gpt->mode, MPC52xx_GPT_MODE_PWM);
85
86         //out_be32(&gpt->pwm, (500<<16) | MPC52xx_GPT_PWM_OP); /* REMOVE ME */
87
88         //out_be32(&gpt->mode, MPC52xx_GPT_MODE_GPIO | (2<<4));
89         //printk("pwm: %p\n", gpt);
90 }
91
92 static void __devinit init_input(struct mpc52xx_gpt *gpt)
93 {
94         out_be32(&gpt->mode,
95                  MPC52xx_GPT_MODE_GPIO |
96                  MPC52xx_GPT_MODE_GPIO_IN);
97 }
98
99 static void  pwm_done(struct mpc52xx_gpt *gpt)
100 {
101         out_be32(&gpt->mode, 0);
102         out_be32(&gpt->count, 0);
103         pwm_width(gpt, 0);
104 }
105
106 static void motorek_action(struct motorek *m, int action_permile)
107 {
108         m->action = action_permile;
109         if (action_permile >= 0) {
110                 pwm_width(m->pwmb, 0);
111                 pwm_width(m->pwmf, +action_permile*PWM_PERIOD/1000);
112         } else {
113                 pwm_width(m->pwmf, 0);
114                 pwm_width(m->pwmb, -action_permile*PWM_PERIOD/1000);
115         }
116 }
117
118 static int __devinit motorek_init(struct motorek *m)
119 {
120         init_pwn(m->pwmf);
121         init_pwn(m->pwmb);
122         init_input(m->irca);
123         init_input(m->ircb);
124         return 0;
125 }
126
127 static int motorek_done(struct motorek *m)
128 {
129         pwm_done(m->pwmf);
130         pwm_done(m->pwmb);
131         return 0;
132 }
133 #define TRANSITION(old, new) (((old) << 2) | new)
134 static const int table[16] = {
135         [TRANSITION(0,1)] = +1,
136         [TRANSITION(1,3)] = +1,
137         [TRANSITION(3,2)] = +1,
138         [TRANSITION(2,0)] = +1,
139
140         [TRANSITION(1,0)] = -1,
141         [TRANSITION(3,1)] = -1,
142         [TRANSITION(2,3)] = -1,
143         [TRANSITION(0,2)] = -1,
144 };
145
146 static irqreturn_t motorek_irq(int irq, void *dev_id)
147 {
148         struct motorek *m = dev_id;
149         int irc_state =
150                 ((in_be32(&m->irca->status) & MPC52xx_GPT_STATUS_PIN) ? 1 : 0) | \
151                 ((in_be32(&m->ircb->status) & MPC52xx_GPT_STATUS_PIN) ? 2 : 0);
152         atomic_add(table[TRANSITION(m->last_irc_state, irc_state)], &m->pos);
153         m->last_irc_state = irc_state;
154         return IRQ_HANDLED;
155 }
156
157 static struct of_device_id mpc5200_gpt_match[] = {
158         { .compatible = "mpc5200-gpt", },
159         { .compatible = "fsl,mpc5200-gpt", },
160         {},
161 };
162
163 struct mpc52xx_gpt __iomem *iomap_gpt_by_phandle_prop(struct device_node *dn, const char *prop)
164 {
165         struct device_node *np;
166         struct mpc52xx_gpt __iomem *gpt = NULL;
167         const phandle *phandle;
168
169         phandle = of_get_property(dn, prop, NULL);
170         if (!phandle)
171                 return NULL;
172
173         np = of_find_node_by_phandle(*phandle);
174         if (!np)
175                 return NULL;
176
177         if (!of_match_node(mpc5200_gpt_match, np)) {
178                 printk(KERN_ERR "property %s doesn't refer to GPT\n", prop);
179                 goto out;
180         }
181         
182         gpt = of_iomap(np, 0);
183 out:
184         of_node_put(np);
185         return gpt;
186 }
187
188 static int __devinit motorek_probe(struct of_device* dev,
189                                    const struct of_device_id *match)
190 {
191         struct device_node *dn = dev->node;
192         struct motorek *m;
193         int err;
194
195         m = kzalloc(sizeof(*m), GFP_KERNEL);
196         if (!m)
197                 return -ENOMEM;
198
199         err = -ENODEV;
200         
201         m->pwmf = iomap_gpt_by_phandle_prop(dn, "pwmf");
202         if (!m->pwmf)
203                 goto err_free;
204         m->pwmb = iomap_gpt_by_phandle_prop(dn, "pwmb");
205         if (!m->pwmb)
206                 goto err_unmap_pf;
207         m->irca = iomap_gpt_by_phandle_prop(dn, "irca");
208         if (!m->irca)
209                 goto err_unmap_pb;
210         m->ircb = iomap_gpt_by_phandle_prop(dn, "ircb");
211         if (!m->ircb)
212                 goto err_unmap_ia;
213         
214         m->irq = irq_of_parse_and_map(dn, 0);
215         if (m->irq == NO_IRQ)
216                 goto err_unmap_ib;
217         err = request_irq(m->irq, motorek_irq, 0, "motorek", m);
218         if (err)
219                 goto err_unmap_ib;
220
221         motorek_init(m);
222
223         platform_set_drvdata(dev, m);
224         err = device_create_file(&dev->dev,&dev_attr_position);
225         if (err)
226                 goto err_irq;
227         err = device_create_file(&dev->dev,&dev_attr_action);
228         if (err)
229                 goto err_irq;
230
231         printk(KERN_NOTICE "Motorek initialized\n");
232
233         return 0;
234
235 err_irq:
236         free_irq(m->irq, m);
237 err_unmap_ib:
238         iounmap(m->pwmb);
239 err_unmap_ia:
240         iounmap(m->pwmf);
241 err_unmap_pb:
242         iounmap(m->pwmb);
243 err_unmap_pf:
244         iounmap(m->pwmf);
245 err_free:
246         kfree(m);
247         return err;
248 }
249
250 static int __devexit motorek_remove(struct of_device* dev)
251 {
252         struct motorek *m;
253
254         printk(KERN_NOTICE "Removing motorek\n");
255         m = platform_get_drvdata(dev);
256         free_irq(m->irq, m);
257         motorek_done(m);
258         kfree(m);
259         return 0;
260 }
261
262 static struct of_device_id motorek_match[] = {
263         { .type = "motorek", },
264         {},
265 };
266 static struct of_platform_driver motorek_driver = {
267         .owner          = THIS_MODULE,
268         .name           = "motorek",
269         .match_table    = motorek_match,
270         .probe          = motorek_probe,
271         .remove         = __devexit_p(motorek_remove),
272 };
273
274
275 static int __init motorek_init_module(void)
276 {
277         int ret;
278         struct of_device *dev;
279         struct device_node *dn;
280
281         for_each_node_by_type(dn, "motorek") {
282                 if (!of_find_device_by_node(dn)) {
283                         dev = of_platform_device_create(dn, NULL, NULL);
284                         if (!dev)
285                                 return -ENOMEM;
286                 }
287         };
288
289         ret = of_register_platform_driver(&motorek_driver);
290         return ret;
291 }
292
293 static void __exit motorek_exit_module(void)
294 {
295         struct of_device *dev;
296         struct device_node *dn;
297
298         for_each_node_by_type(dn, "motorek") {
299                 while ((dev = of_find_device_by_node(dn))) {
300                         of_device_unregister(dev);
301                 }
302         }
303         of_unregister_platform_driver(&motorek_driver);
304 }
305
306 module_init(motorek_init_module);
307 module_exit(motorek_exit_module);
308
309
310 MODULE_LICENSE("GPL v2");
311 MODULE_VERSION("0.1");
312 MODULE_AUTHOR("Michal Sojka <sojkam1@fel.cvut.cz>");