GNU Linux-libre 6.9.1-gnu
[releases.git] / drivers / staging / greybus / arche-platform.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Arche Platform driver to enable Unipro link.
4  *
5  * Copyright 2014-2015 Google Inc.
6  * Copyright 2014-2015 Linaro Ltd.
7  */
8
9 #include <linux/clk.h>
10 #include <linux/delay.h>
11 #include <linux/gpio/consumer.h>
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/of_platform.h>
15 #include <linux/pinctrl/consumer.h>
16 #include <linux/platform_device.h>
17 #include <linux/pm.h>
18 #include <linux/interrupt.h>
19 #include <linux/irq.h>
20 #include <linux/suspend.h>
21 #include <linux/time.h>
22 #include <linux/greybus.h>
23 #include <linux/of.h>
24 #include "arche_platform.h"
25
26 #if IS_ENABLED(CONFIG_USB_HSIC_USB3613)
27 #include <linux/usb/usb3613.h>
28 #else
29 static inline int usb3613_hub_mode_ctrl(bool unused)
30 {
31         return 0;
32 }
33 #endif
34
35 #define WD_COLDBOOT_PULSE_WIDTH_MS      30
36
37 enum svc_wakedetect_state {
38         WD_STATE_IDLE,                  /* Default state = pulled high/low */
39         WD_STATE_BOOT_INIT,             /* WD = falling edge (low) */
40         WD_STATE_COLDBOOT_TRIG,         /* WD = rising edge (high), > 30msec */
41         WD_STATE_STANDBYBOOT_TRIG,      /* As of now not used ?? */
42         WD_STATE_COLDBOOT_START,        /* Cold boot process started */
43         WD_STATE_STANDBYBOOT_START,     /* Not used */
44 };
45
46 struct arche_platform_drvdata {
47         /* Control GPIO signals to and from AP <=> SVC */
48         struct gpio_desc *svc_reset;
49         bool is_reset_act_hi;
50         struct gpio_desc *svc_sysboot;
51         struct gpio_desc *wake_detect; /* bi-dir,maps to WAKE_MOD & WAKE_FRAME signals */
52
53         enum arche_platform_state state;
54
55         struct gpio_desc *svc_refclk_req;
56         struct clk *svc_ref_clk;
57
58         struct pinctrl *pinctrl;
59         struct pinctrl_state *pin_default;
60
61         int num_apbs;
62
63         enum svc_wakedetect_state wake_detect_state;
64         int wake_detect_irq;
65         spinlock_t wake_lock;                   /* Protect wake_detect_state */
66         struct mutex platform_state_mutex;      /* Protect state */
67         unsigned long wake_detect_start;
68         struct notifier_block pm_notifier;
69
70         struct device *dev;
71 };
72
73 /* Requires calling context to hold arche_pdata->platform_state_mutex */
74 static void arche_platform_set_state(struct arche_platform_drvdata *arche_pdata,
75                                      enum arche_platform_state state)
76 {
77         arche_pdata->state = state;
78 }
79
80 /* Requires arche_pdata->wake_lock is held by calling context */
81 static void arche_platform_set_wake_detect_state(struct arche_platform_drvdata *arche_pdata,
82                                                  enum svc_wakedetect_state state)
83 {
84         arche_pdata->wake_detect_state = state;
85 }
86
87 static inline void svc_reset_onoff(struct gpio_desc *gpio, bool onoff)
88 {
89         gpiod_set_raw_value(gpio, onoff);
90 }
91
92 static int apb_cold_boot(struct device *dev, void *data)
93 {
94         int ret;
95
96         ret = apb_ctrl_coldboot(dev);
97         if (ret)
98                 dev_warn(dev, "failed to coldboot\n");
99
100         /*Child nodes are independent, so do not exit coldboot operation */
101         return 0;
102 }
103
104 static int apb_poweroff(struct device *dev, void *data)
105 {
106         apb_ctrl_poweroff(dev);
107
108         /* Enable HUB3613 into HUB mode. */
109         if (usb3613_hub_mode_ctrl(false))
110                 dev_warn(dev, "failed to control hub device\n");
111
112         return 0;
113 }
114
115 static void arche_platform_wd_irq_en(struct arche_platform_drvdata *arche_pdata)
116 {
117         /* Enable interrupt here, to read event back from SVC */
118         enable_irq(arche_pdata->wake_detect_irq);
119 }
120
121 static irqreturn_t arche_platform_wd_irq_thread(int irq, void *devid)
122 {
123         struct arche_platform_drvdata *arche_pdata = devid;
124         unsigned long flags;
125
126         spin_lock_irqsave(&arche_pdata->wake_lock, flags);
127         if (arche_pdata->wake_detect_state != WD_STATE_COLDBOOT_TRIG) {
128                 /* Something is wrong */
129                 spin_unlock_irqrestore(&arche_pdata->wake_lock, flags);
130                 return IRQ_HANDLED;
131         }
132
133         arche_platform_set_wake_detect_state(arche_pdata,
134                                              WD_STATE_COLDBOOT_START);
135         spin_unlock_irqrestore(&arche_pdata->wake_lock, flags);
136
137         /* It should complete power cycle, so first make sure it is poweroff */
138         device_for_each_child(arche_pdata->dev, NULL, apb_poweroff);
139
140         /* Bring APB out of reset: cold boot sequence */
141         device_for_each_child(arche_pdata->dev, NULL, apb_cold_boot);
142
143         /* Enable HUB3613 into HUB mode. */
144         if (usb3613_hub_mode_ctrl(true))
145                 dev_warn(arche_pdata->dev, "failed to control hub device\n");
146
147         spin_lock_irqsave(&arche_pdata->wake_lock, flags);
148         arche_platform_set_wake_detect_state(arche_pdata, WD_STATE_IDLE);
149         spin_unlock_irqrestore(&arche_pdata->wake_lock, flags);
150
151         return IRQ_HANDLED;
152 }
153
154 static irqreturn_t arche_platform_wd_irq(int irq, void *devid)
155 {
156         struct arche_platform_drvdata *arche_pdata = devid;
157         unsigned long flags;
158
159         spin_lock_irqsave(&arche_pdata->wake_lock, flags);
160
161         if (gpiod_get_value(arche_pdata->wake_detect)) {
162                 /* wake/detect rising */
163
164                 /*
165                  * If wake/detect line goes high after low, within less than
166                  * 30msec, then standby boot sequence is initiated, which is not
167                  * supported/implemented as of now. So ignore it.
168                  */
169                 if (arche_pdata->wake_detect_state == WD_STATE_BOOT_INIT) {
170                         if (time_before(jiffies,
171                                         arche_pdata->wake_detect_start +
172                                         msecs_to_jiffies(WD_COLDBOOT_PULSE_WIDTH_MS))) {
173                                 arche_platform_set_wake_detect_state(arche_pdata,
174                                                                      WD_STATE_IDLE);
175                         } else {
176                                 /*
177                                  * Check we are not in middle of irq thread
178                                  * already
179                                  */
180                                 if (arche_pdata->wake_detect_state !=
181                                                 WD_STATE_COLDBOOT_START) {
182                                         arche_platform_set_wake_detect_state(arche_pdata,
183                                                                              WD_STATE_COLDBOOT_TRIG);
184                                         spin_unlock_irqrestore(&arche_pdata->wake_lock,
185                                                                flags);
186                                         return IRQ_WAKE_THREAD;
187                                 }
188                         }
189                 }
190         } else {
191                 /* wake/detect falling */
192                 if (arche_pdata->wake_detect_state == WD_STATE_IDLE) {
193                         arche_pdata->wake_detect_start = jiffies;
194                         /*
195                          * In the beginning, when wake/detect goes low
196                          * (first time), we assume it is meant for coldboot
197                          * and set the flag. If wake/detect line stays low
198                          * beyond 30msec, then it is coldboot else fallback
199                          * to standby boot.
200                          */
201                         arche_platform_set_wake_detect_state(arche_pdata,
202                                                              WD_STATE_BOOT_INIT);
203                 }
204         }
205
206         spin_unlock_irqrestore(&arche_pdata->wake_lock, flags);
207
208         return IRQ_HANDLED;
209 }
210
211 /*
212  * Requires arche_pdata->platform_state_mutex to be held
213  */
214 static int
215 arche_platform_coldboot_seq(struct arche_platform_drvdata *arche_pdata)
216 {
217         int ret;
218
219         if (arche_pdata->state == ARCHE_PLATFORM_STATE_ACTIVE)
220                 return 0;
221
222         dev_info(arche_pdata->dev, "Booting from cold boot state\n");
223
224         svc_reset_onoff(arche_pdata->svc_reset, arche_pdata->is_reset_act_hi);
225
226         gpiod_set_value(arche_pdata->svc_sysboot, 0);
227         usleep_range(100, 200);
228
229         ret = clk_prepare_enable(arche_pdata->svc_ref_clk);
230         if (ret) {
231                 dev_err(arche_pdata->dev, "failed to enable svc_ref_clk: %d\n",
232                         ret);
233                 return ret;
234         }
235
236         /* bring SVC out of reset */
237         svc_reset_onoff(arche_pdata->svc_reset, !arche_pdata->is_reset_act_hi);
238
239         arche_platform_set_state(arche_pdata, ARCHE_PLATFORM_STATE_ACTIVE);
240
241         return 0;
242 }
243
244 /*
245  * Requires arche_pdata->platform_state_mutex to be held
246  */
247 static int
248 arche_platform_fw_flashing_seq(struct arche_platform_drvdata *arche_pdata)
249 {
250         int ret;
251
252         if (arche_pdata->state == ARCHE_PLATFORM_STATE_FW_FLASHING)
253                 return 0;
254
255         dev_info(arche_pdata->dev, "Switching to FW flashing state\n");
256
257         svc_reset_onoff(arche_pdata->svc_reset, arche_pdata->is_reset_act_hi);
258
259         gpiod_set_value(arche_pdata->svc_sysboot, 1);
260
261         usleep_range(100, 200);
262
263         ret = clk_prepare_enable(arche_pdata->svc_ref_clk);
264         if (ret) {
265                 dev_err(arche_pdata->dev, "failed to enable svc_ref_clk: %d\n",
266                         ret);
267                 return ret;
268         }
269
270         svc_reset_onoff(arche_pdata->svc_reset, !arche_pdata->is_reset_act_hi);
271
272         arche_platform_set_state(arche_pdata, ARCHE_PLATFORM_STATE_FW_FLASHING);
273
274         return 0;
275 }
276
277 /*
278  * Requires arche_pdata->platform_state_mutex to be held
279  */
280 static void
281 arche_platform_poweroff_seq(struct arche_platform_drvdata *arche_pdata)
282 {
283         unsigned long flags;
284
285         if (arche_pdata->state == ARCHE_PLATFORM_STATE_OFF)
286                 return;
287
288         /* If in fw_flashing mode, then no need to repeate things again */
289         if (arche_pdata->state != ARCHE_PLATFORM_STATE_FW_FLASHING) {
290                 disable_irq(arche_pdata->wake_detect_irq);
291
292                 spin_lock_irqsave(&arche_pdata->wake_lock, flags);
293                 arche_platform_set_wake_detect_state(arche_pdata,
294                                                      WD_STATE_IDLE);
295                 spin_unlock_irqrestore(&arche_pdata->wake_lock, flags);
296         }
297
298         clk_disable_unprepare(arche_pdata->svc_ref_clk);
299
300         /* As part of exit, put APB back in reset state */
301         svc_reset_onoff(arche_pdata->svc_reset, arche_pdata->is_reset_act_hi);
302
303         arche_platform_set_state(arche_pdata, ARCHE_PLATFORM_STATE_OFF);
304 }
305
306 static ssize_t state_store(struct device *dev,
307                            struct device_attribute *attr,
308                            const char *buf, size_t count)
309 {
310         struct arche_platform_drvdata *arche_pdata = dev_get_drvdata(dev);
311         int ret = 0;
312
313         mutex_lock(&arche_pdata->platform_state_mutex);
314
315         if (sysfs_streq(buf, "off")) {
316                 if (arche_pdata->state == ARCHE_PLATFORM_STATE_OFF)
317                         goto exit;
318
319                 /*  If SVC goes down, bring down APB's as well */
320                 device_for_each_child(arche_pdata->dev, NULL, apb_poweroff);
321
322                 arche_platform_poweroff_seq(arche_pdata);
323
324         } else if (sysfs_streq(buf, "active")) {
325                 if (arche_pdata->state == ARCHE_PLATFORM_STATE_ACTIVE)
326                         goto exit;
327
328                 /* First we want to make sure we power off everything
329                  * and then activate back again
330                  */
331                 device_for_each_child(arche_pdata->dev, NULL, apb_poweroff);
332                 arche_platform_poweroff_seq(arche_pdata);
333
334                 arche_platform_wd_irq_en(arche_pdata);
335                 ret = arche_platform_coldboot_seq(arche_pdata);
336                 if (ret)
337                         goto exit;
338
339         } else if (sysfs_streq(buf, "standby")) {
340                 if (arche_pdata->state == ARCHE_PLATFORM_STATE_STANDBY)
341                         goto exit;
342
343                 dev_warn(arche_pdata->dev, "standby state not supported\n");
344         } else if (sysfs_streq(buf, "fw_flashing")) {
345                 if (arche_pdata->state == ARCHE_PLATFORM_STATE_FW_FLASHING)
346                         goto exit;
347
348                 /*
349                  * Here we only control SVC.
350                  *
351                  * In case of FW_FLASHING mode we do not want to control
352                  * APBs, as in case of V2, SPI bus is shared between both
353                  * the APBs. So let user chose which APB he wants to flash.
354                  */
355                 arche_platform_poweroff_seq(arche_pdata);
356
357                 ret = arche_platform_fw_flashing_seq(arche_pdata);
358                 if (ret)
359                         goto exit;
360         } else {
361                 dev_err(arche_pdata->dev, "unknown state\n");
362                 ret = -EINVAL;
363         }
364
365 exit:
366         mutex_unlock(&arche_pdata->platform_state_mutex);
367         return ret ? ret : count;
368 }
369
370 static ssize_t state_show(struct device *dev,
371                           struct device_attribute *attr, char *buf)
372 {
373         struct arche_platform_drvdata *arche_pdata = dev_get_drvdata(dev);
374
375         switch (arche_pdata->state) {
376         case ARCHE_PLATFORM_STATE_OFF:
377                 return sprintf(buf, "off\n");
378         case ARCHE_PLATFORM_STATE_ACTIVE:
379                 return sprintf(buf, "active\n");
380         case ARCHE_PLATFORM_STATE_STANDBY:
381                 return sprintf(buf, "standby\n");
382         case ARCHE_PLATFORM_STATE_FW_FLASHING:
383                 return sprintf(buf, "fw_flashing\n");
384         default:
385                 return sprintf(buf, "unknown state\n");
386         }
387 }
388
389 static DEVICE_ATTR_RW(state);
390
391 static int arche_platform_pm_notifier(struct notifier_block *notifier,
392                                       unsigned long pm_event, void *unused)
393 {
394         struct arche_platform_drvdata *arche_pdata =
395                 container_of(notifier, struct arche_platform_drvdata,
396                              pm_notifier);
397         int ret = NOTIFY_DONE;
398
399         mutex_lock(&arche_pdata->platform_state_mutex);
400         switch (pm_event) {
401         case PM_SUSPEND_PREPARE:
402                 if (arche_pdata->state != ARCHE_PLATFORM_STATE_ACTIVE) {
403                         ret = NOTIFY_STOP;
404                         break;
405                 }
406                 device_for_each_child(arche_pdata->dev, NULL, apb_poweroff);
407                 arche_platform_poweroff_seq(arche_pdata);
408                 break;
409         case PM_POST_SUSPEND:
410                 if (arche_pdata->state != ARCHE_PLATFORM_STATE_OFF)
411                         break;
412
413                 arche_platform_wd_irq_en(arche_pdata);
414                 arche_platform_coldboot_seq(arche_pdata);
415                 break;
416         default:
417                 break;
418         }
419         mutex_unlock(&arche_pdata->platform_state_mutex);
420
421         return ret;
422 }
423
424 static int arche_platform_probe(struct platform_device *pdev)
425 {
426         struct arche_platform_drvdata *arche_pdata;
427         struct device *dev = &pdev->dev;
428         struct device_node *np = dev->of_node;
429         int ret;
430         unsigned int flags;
431
432         arche_pdata = devm_kzalloc(&pdev->dev, sizeof(*arche_pdata),
433                                    GFP_KERNEL);
434         if (!arche_pdata)
435                 return -ENOMEM;
436
437         /* setup svc reset gpio */
438         arche_pdata->is_reset_act_hi = of_property_read_bool(np,
439                                                              "svc,reset-active-high");
440         if (arche_pdata->is_reset_act_hi)
441                 flags = GPIOD_OUT_HIGH;
442         else
443                 flags = GPIOD_OUT_LOW;
444
445         arche_pdata->svc_reset = devm_gpiod_get(dev, "svc,reset", flags);
446         if (IS_ERR(arche_pdata->svc_reset)) {
447                 ret = PTR_ERR(arche_pdata->svc_reset);
448                 dev_err(dev, "failed to request svc-reset GPIO: %d\n", ret);
449                 return ret;
450         }
451         arche_platform_set_state(arche_pdata, ARCHE_PLATFORM_STATE_OFF);
452
453         arche_pdata->svc_sysboot = devm_gpiod_get(dev, "svc,sysboot",
454                                                   GPIOD_OUT_LOW);
455         if (IS_ERR(arche_pdata->svc_sysboot)) {
456                 ret = PTR_ERR(arche_pdata->svc_sysboot);
457                 dev_err(dev, "failed to request sysboot0 GPIO: %d\n", ret);
458                 return ret;
459         }
460
461         /* setup the clock request gpio first */
462         arche_pdata->svc_refclk_req = devm_gpiod_get(dev, "svc,refclk-req",
463                                                      GPIOD_IN);
464         if (IS_ERR(arche_pdata->svc_refclk_req)) {
465                 ret = PTR_ERR(arche_pdata->svc_refclk_req);
466                 dev_err(dev, "failed to request svc-clk-req GPIO: %d\n", ret);
467                 return ret;
468         }
469
470         /* setup refclk2 to follow the pin */
471         arche_pdata->svc_ref_clk = devm_clk_get(dev, "svc_ref_clk");
472         if (IS_ERR(arche_pdata->svc_ref_clk)) {
473                 ret = PTR_ERR(arche_pdata->svc_ref_clk);
474                 dev_err(dev, "failed to get svc_ref_clk: %d\n", ret);
475                 return ret;
476         }
477
478         platform_set_drvdata(pdev, arche_pdata);
479
480         arche_pdata->num_apbs = of_get_child_count(np);
481         dev_dbg(dev, "Number of APB's available - %d\n", arche_pdata->num_apbs);
482
483         arche_pdata->wake_detect = devm_gpiod_get(dev, "svc,wake-detect",
484                                                   GPIOD_IN);
485         if (IS_ERR(arche_pdata->wake_detect)) {
486                 ret = PTR_ERR(arche_pdata->wake_detect);
487                 dev_err(dev, "Failed requesting wake_detect GPIO: %d\n", ret);
488                 return ret;
489         }
490
491         arche_platform_set_wake_detect_state(arche_pdata, WD_STATE_IDLE);
492
493         arche_pdata->dev = &pdev->dev;
494
495         spin_lock_init(&arche_pdata->wake_lock);
496         mutex_init(&arche_pdata->platform_state_mutex);
497         arche_pdata->wake_detect_irq =
498                 gpiod_to_irq(arche_pdata->wake_detect);
499
500         ret = devm_request_threaded_irq(dev, arche_pdata->wake_detect_irq,
501                                         arche_platform_wd_irq,
502                                         arche_platform_wd_irq_thread,
503                                         IRQF_TRIGGER_FALLING |
504                                         IRQF_TRIGGER_RISING | IRQF_ONESHOT,
505                                         dev_name(dev), arche_pdata);
506         if (ret) {
507                 dev_err(dev, "failed to request wake detect IRQ %d\n", ret);
508                 return ret;
509         }
510         disable_irq(arche_pdata->wake_detect_irq);
511
512         ret = device_create_file(dev, &dev_attr_state);
513         if (ret) {
514                 dev_err(dev, "failed to create state file in sysfs\n");
515                 return ret;
516         }
517
518         ret = of_platform_populate(np, NULL, NULL, dev);
519         if (ret) {
520                 dev_err(dev, "failed to populate child nodes %d\n", ret);
521                 goto err_device_remove;
522         }
523
524         arche_pdata->pm_notifier.notifier_call = arche_platform_pm_notifier;
525         ret = register_pm_notifier(&arche_pdata->pm_notifier);
526
527         if (ret) {
528                 dev_err(dev, "failed to register pm notifier %d\n", ret);
529                 goto err_device_remove;
530         }
531
532         /* Explicitly power off if requested */
533         if (!of_property_read_bool(pdev->dev.of_node, "arche,init-off")) {
534                 mutex_lock(&arche_pdata->platform_state_mutex);
535                 ret = arche_platform_coldboot_seq(arche_pdata);
536                 if (ret) {
537                         dev_err(dev, "Failed to cold boot svc %d\n", ret);
538                         goto err_coldboot;
539                 }
540                 arche_platform_wd_irq_en(arche_pdata);
541                 mutex_unlock(&arche_pdata->platform_state_mutex);
542         }
543
544         dev_info(dev, "Device registered successfully\n");
545         return 0;
546
547 err_coldboot:
548         mutex_unlock(&arche_pdata->platform_state_mutex);
549 err_device_remove:
550         device_remove_file(&pdev->dev, &dev_attr_state);
551         return ret;
552 }
553
554 static int arche_remove_child(struct device *dev, void *unused)
555 {
556         struct platform_device *pdev = to_platform_device(dev);
557
558         platform_device_unregister(pdev);
559
560         return 0;
561 }
562
563 static void arche_platform_remove(struct platform_device *pdev)
564 {
565         struct arche_platform_drvdata *arche_pdata = platform_get_drvdata(pdev);
566
567         unregister_pm_notifier(&arche_pdata->pm_notifier);
568         device_remove_file(&pdev->dev, &dev_attr_state);
569         device_for_each_child(&pdev->dev, NULL, arche_remove_child);
570         arche_platform_poweroff_seq(arche_pdata);
571
572         if (usb3613_hub_mode_ctrl(false))
573                 dev_warn(arche_pdata->dev, "failed to control hub device\n");
574 }
575
576 static __maybe_unused int arche_platform_suspend(struct device *dev)
577 {
578         /*
579          * If timing profile premits, we may shutdown bridge
580          * completely
581          *
582          * TODO: sequence ??
583          *
584          * Also, need to make sure we meet precondition for unipro suspend
585          * Precondition: Definition ???
586          */
587         return 0;
588 }
589
590 static __maybe_unused int arche_platform_resume(struct device *dev)
591 {
592         /*
593          * At least for ES2 we have to meet the delay requirement between
594          * unipro switch and AP bridge init, depending on whether bridge is in
595          * OFF state or standby state.
596          *
597          * Based on whether bridge is in standby or OFF state we may have to
598          * assert multiple signals. Please refer to WDM spec, for more info.
599          *
600          */
601         return 0;
602 }
603
604 static void arche_platform_shutdown(struct platform_device *pdev)
605 {
606         struct arche_platform_drvdata *arche_pdata = platform_get_drvdata(pdev);
607
608         arche_platform_poweroff_seq(arche_pdata);
609
610         usb3613_hub_mode_ctrl(false);
611 }
612
613 static SIMPLE_DEV_PM_OPS(arche_platform_pm_ops,
614                         arche_platform_suspend,
615                         arche_platform_resume);
616
617 static const struct of_device_id arche_platform_of_match[] = {
618         /* Use PID/VID of SVC device */
619         { .compatible = "google,arche-platform", },
620         { },
621 };
622
623 static const struct of_device_id arche_combined_id[] = {
624         /* Use PID/VID of SVC device */
625         { .compatible = "google,arche-platform", },
626         { .compatible = "usbffff,2", },
627         { },
628 };
629 MODULE_DEVICE_TABLE(of, arche_combined_id);
630
631 static struct platform_driver arche_platform_device_driver = {
632         .probe          = arche_platform_probe,
633         .remove_new     = arche_platform_remove,
634         .shutdown       = arche_platform_shutdown,
635         .driver         = {
636                 .name   = "arche-platform-ctrl",
637                 .pm     = &arche_platform_pm_ops,
638                 .of_match_table = arche_platform_of_match,
639         }
640 };
641
642 static int __init arche_init(void)
643 {
644         int retval;
645
646         retval = platform_driver_register(&arche_platform_device_driver);
647         if (retval)
648                 return retval;
649
650         retval = arche_apb_init();
651         if (retval)
652                 platform_driver_unregister(&arche_platform_device_driver);
653
654         return retval;
655 }
656 module_init(arche_init);
657
658 static void __exit arche_exit(void)
659 {
660         arche_apb_exit();
661         platform_driver_unregister(&arche_platform_device_driver);
662 }
663 module_exit(arche_exit);
664
665 MODULE_LICENSE("GPL v2");
666 MODULE_AUTHOR("Vaibhav Hiremath <vaibhav.hiremath@linaro.org>");
667 MODULE_DESCRIPTION("Arche Platform Driver");