blob: ca99b1a0698c4b4b04281685566bc37c4d1057c0 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13/*
14 * msm_dsps - control DSPS clocks, gpios and vregs.
15 *
16 */
17
18#include <linux/types.h>
19#include <linux/slab.h>
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/cdev.h>
23#include <linux/fs.h>
24#include <linux/platform_device.h>
25#include <linux/err.h>
26#include <linux/delay.h>
27#include <linux/clk.h>
28#include <linux/gpio.h>
29#include <linux/string.h>
30#include <linux/uaccess.h>
31#include <linux/io.h>
32#include <linux/msm_dsps.h>
33
Wentao Xua55500b2011-08-16 18:15:04 -040034#include <mach/irqs.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070035#include <mach/peripheral-loader.h>
36#include <mach/msm_iomap.h>
Wentao Xua55500b2011-08-16 18:15:04 -040037#include <mach/msm_smsm.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038#include <mach/msm_dsps.h>
Wentao Xua55500b2011-08-16 18:15:04 -040039#include <mach/subsystem_restart.h>
40#include <mach/subsystem_notif.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041
42#define DRV_NAME "msm_dsps"
Wentao Xua55500b2011-08-16 18:15:04 -040043#define DRV_VERSION "3.00"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070044
45#define PPSS_PAUSE_REG 0x1804
46
47#define PPSS_TIMER0_32KHZ_REG 0x1004
48#define PPSS_TIMER0_20MHZ_REG 0x0804
49
50/**
51 * Driver Context
52 *
53 * @dev_class - device class.
54 * @dev_num - device major & minor number.
55 * @dev - the device.
56 * @cdev - character device for user interface.
57 * @pdata - platform data.
58 * @pil - handle to DSPS Firmware loader.
59 * @is_on - DSPS is on.
60 * @ref_count - open/close reference count.
61 * @ppss_base - ppss registers virtual base address.
62 */
63struct dsps_drv {
64
65 struct class *dev_class;
66 dev_t dev_num;
67 struct device *dev;
68 struct cdev *cdev;
69
70 struct msm_dsps_platform_data *pdata;
71
72 void *pil;
73
74 int is_on;
75 int ref_count;
76
77 void __iomem *ppss_base;
78};
79
80/**
81 * Driver context.
82 */
83static struct dsps_drv *drv;
84
85/**
Wentao Xua55500b2011-08-16 18:15:04 -040086 * self-initiated shutdown flag
87 */
88static int dsps_crash_shutdown_g;
89
90
91static void dsps_fatal_handler(struct work_struct *work);
92
93/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070094 * Load DSPS Firmware.
95 */
96static int dsps_load(const char *name)
97{
98 pr_debug("%s.\n", __func__);
99
100 drv->pil = pil_get(name);
101
102 if (IS_ERR(drv->pil)) {
103 pr_err("%s: fail to load DSPS firmware %s.\n", __func__, name);
104 return -ENODEV;
105 }
106
107 return 0;
108}
109
110/**
111 * Unload DSPS Firmware.
112 */
113static void dsps_unload(void)
114{
115 pr_debug("%s.\n", __func__);
116
117 pil_put(drv->pil);
118}
119
120/**
121 * Suspend DSPS CPU.
122 */
123static void dsps_suspend(void)
124{
125 pr_debug("%s.\n", __func__);
126
127 writel_relaxed(1, drv->ppss_base + PPSS_PAUSE_REG);
128 mb(); /* Make sure write commited before ioctl returns. */
129}
130
131/**
132 * Resume DSPS CPU.
133 */
134static void dsps_resume(void)
135{
136 pr_debug("%s.\n", __func__);
137
138 writel_relaxed(0, drv->ppss_base + PPSS_PAUSE_REG);
139 mb(); /* Make sure write commited before ioctl returns. */
140}
141
142/**
143 * Read DSPS slow timer.
144 */
145static u32 dsps_read_slow_timer(void)
146{
147 u32 val;
148
149 val = readl_relaxed(drv->ppss_base + PPSS_TIMER0_32KHZ_REG);
150 rmb(); /* order reads from the user output buffer */
151
152 pr_debug("%s.count=%d.\n", __func__, val);
153
154 return val;
155}
156
157/**
158 * Read DSPS fast timer.
159 */
160static u32 dsps_read_fast_timer(void)
161{
162 u32 val;
163
164 val = readl_relaxed(drv->ppss_base + PPSS_TIMER0_20MHZ_REG);
165 rmb(); /* order reads from the user output buffer */
166
167 pr_debug("%s.count=%d.\n", __func__, val);
168
169 return val;
170}
171
172/**
173 * Power on request.
174 *
175 * Set clocks to ON.
176 * Set sensors chip-select GPIO to non-reset (on) value.
177 *
178 */
179static int dsps_power_on_handler(void)
180{
181 int ret = 0;
182 int i, ci, gi, ri;
183
184 pr_debug("%s.\n", __func__);
185
186 if (drv->is_on) {
187 pr_debug("%s: already ON.\n", __func__);
188 return 0;
189 }
190
191 for (ci = 0; ci < drv->pdata->clks_num; ci++) {
192 const char *name = drv->pdata->clks[ci].name;
193 u32 rate = drv->pdata->clks[ci].rate;
194 struct clk *clock = drv->pdata->clks[ci].clock;
195
196 if (clock == NULL)
197 continue;
198
199 if (rate > 0) {
200 ret = clk_set_rate(clock, rate);
201 pr_debug("%s: clk %s set rate %d.",
202 __func__, name, rate);
203 if (ret) {
204 pr_err("%s: clk %s set rate %d. err=%d.",
205 __func__, name, rate, ret);
206 goto clk_err;
207 }
208
209 }
210
211 ret = clk_enable(clock);
212 if (ret) {
213 pr_err("%s: enable clk %s err %d.",
214 __func__, name, ret);
215 goto clk_err;
216 }
217 }
218
219 for (gi = 0; gi < drv->pdata->gpios_num; gi++) {
220 const char *name = drv->pdata->gpios[gi].name;
221 int num = drv->pdata->gpios[gi].num;
222 int val = drv->pdata->gpios[gi].on_val;
223 int is_owner = drv->pdata->gpios[gi].is_owner;
224
225 if (!is_owner)
226 continue;
227
228 ret = gpio_direction_output(num, val);
229 if (ret) {
230 pr_err("%s: set GPIO %s num %d to %d err %d.",
231 __func__, name, num, val, ret);
232 goto gpio_err;
233 }
234 }
235
236 for (ri = 0; ri < drv->pdata->regs_num; ri++) {
237 const char *name = drv->pdata->regs[ri].name;
238 struct regulator *reg = drv->pdata->regs[ri].reg;
239 int volt = drv->pdata->regs[ri].volt;
240
241 if (reg == NULL)
242 continue;
243
244 pr_debug("%s: set regulator %s.", __func__, name);
245
246 ret = regulator_set_voltage(reg, volt, volt);
247
248 if (ret) {
249 pr_err("%s: set regulator %s voltage %d err = %d.\n",
250 __func__, name, volt, ret);
251 goto reg_err;
252 }
253
254 ret = regulator_enable(reg);
255 if (ret) {
256 pr_err("%s: enable regulator %s err = %d.\n",
257 __func__, name, ret);
258 goto reg_err;
259 }
260 }
261
262 drv->is_on = true;
263
264 return 0;
265
266 /*
267 * If failling to set ANY clock/gpio/regulator to ON then we set
268 * them back to OFF to avoid consuming power for unused
269 * clocks/gpios/regulators.
270 */
271reg_err:
272 for (i = 0; i < ri; i++) {
273 struct regulator *reg = drv->pdata->regs[ri].reg;
274
275 if (reg == NULL)
276 continue;
277
278 regulator_disable(reg);
279 }
280
281gpio_err:
282 for (i = 0; i < gi; i++) {
283 int num = drv->pdata->gpios[i].num;
284 int val = drv->pdata->gpios[i].off_val;
285 int is_owner = drv->pdata->gpios[i].is_owner;
286
287 if (!is_owner)
288 continue;
289
290 ret = gpio_direction_output(num, val);
291 }
292
293clk_err:
294 for (i = 0; i < ci; i++) {
295 struct clk *clock = drv->pdata->clks[i].clock;
296
297 if (clock == NULL)
298 continue;
299
300 clk_disable(clock);
301 }
302
303 return -ENODEV;
304}
305
306/**
307 * Power off request.
308 *
309 * Set clocks to OFF.
310 * Set sensors chip-select GPIO to reset (off) value.
311 *
312 */
313static int dsps_power_off_handler(void)
314{
315 int ret;
316 int i;
317
318 pr_debug("%s.\n", __func__);
319
320 if (!drv->is_on) {
321 pr_debug("%s: already OFF.\n", __func__);
322 return 0;
323 }
324
325 for (i = 0; i < drv->pdata->clks_num; i++)
326 if (drv->pdata->clks[i].clock) {
327 const char *name = drv->pdata->clks[i].name;
328
329 pr_debug("%s: set clk %s off.", __func__, name);
330 clk_disable(drv->pdata->clks[i].clock);
331 }
332
333 for (i = 0; i < drv->pdata->regs_num; i++)
334 if (drv->pdata->regs[i].reg) {
335 const char *name = drv->pdata->regs[i].name;
336
337 pr_debug("%s: set regulator %s off.", __func__, name);
338 regulator_disable(drv->pdata->regs[i].reg);
339 }
340
341 /* Clocks on/off has reference count but GPIOs don't. */
342 drv->is_on = false;
343
344 for (i = 0; i < drv->pdata->gpios_num; i++) {
345 const char *name = drv->pdata->gpios[i].name;
346 int num = drv->pdata->gpios[i].num;
347 int val = drv->pdata->gpios[i].off_val;
348
349 pr_debug("%s: set gpio %s off.", __func__, name);
350
351 ret = gpio_direction_output(num, val);
352 if (ret) {
353 pr_err("%s: set GPIO %s err %d.", __func__, name, ret);
354 return ret;
355 }
356 }
357
358 return 0;
359}
360
Wentao Xua55500b2011-08-16 18:15:04 -0400361static DECLARE_WORK(dsps_fatal_work, dsps_fatal_handler);
362
363/**
364 * Watchdog interrupt handler
365 *
366 */
367static irqreturn_t dsps_wdog_bite_irq(int irq, void *dev_id)
368{
369 pr_debug("%s\n", __func__);
370 (void)schedule_work(&dsps_fatal_work);
371 disable_irq_nosync(irq);
372 return IRQ_HANDLED;
373}
374
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375/**
376 * IO Control - handle commands from client.
377 *
378 */
379static long dsps_ioctl(struct file *file,
380 unsigned int cmd, unsigned long arg)
381{
382 int ret = 0;
383 u32 val = 0;
384
385 pr_debug("%s.\n", __func__);
386
387 switch (cmd) {
388 case DSPS_IOCTL_ON:
389 ret = dsps_power_on_handler();
390 dsps_resume();
391 break;
392 case DSPS_IOCTL_OFF:
393 if (!drv->pdata->dsps_pwr_ctl_en) {
394 dsps_suspend();
395 ret = dsps_power_off_handler();
396 }
397 break;
398 case DSPS_IOCTL_READ_SLOW_TIMER:
399 val = dsps_read_slow_timer();
400 ret = put_user(val, (u32 __user *) arg);
401 break;
402 case DSPS_IOCTL_READ_FAST_TIMER:
403 val = dsps_read_fast_timer();
404 ret = put_user(val, (u32 __user *) arg);
405 break;
Wentao Xua55500b2011-08-16 18:15:04 -0400406 case DSPS_IOCTL_RESET:
407 dsps_fatal_handler(NULL);
408 ret = 0;
409 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700410 default:
411 ret = -EINVAL;
412 break;
413 }
414
415 return ret;
416}
417
418/**
419 * allocate resources.
420 * @pdev - pointer to platform device.
421 */
422static int dsps_alloc_resources(struct platform_device *pdev)
423{
424 int ret = -ENODEV;
425 struct resource *ppss_res;
Wentao Xua55500b2011-08-16 18:15:04 -0400426 struct resource *ppss_wdog;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700427 int i;
428
429 pr_debug("%s.\n", __func__);
430
431 if ((drv->pdata->signature != DSPS_SIGNATURE)) {
432 pr_err("%s: invalid signature for pdata.", __func__);
433 return -EINVAL;
434 }
435
436 ppss_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
437 "ppss_reg");
438 if (!ppss_res) {
439 pr_err("%s: failed to get ppss_reg resource.\n", __func__);
440 return -EINVAL;
441 }
442
443 for (i = 0; i < drv->pdata->clks_num; i++) {
444 const char *name = drv->pdata->clks[i].name;
445 struct clk *clock;
446
447 drv->pdata->clks[i].clock = NULL;
448
449 pr_debug("%s: get clk %s.", __func__, name);
450
451 clock = clk_get(drv->dev, name);
452 if (IS_ERR(clock)) {
453 pr_err("%s: can't get clk %s.", __func__, name);
454 goto clk_err;
455 }
456 drv->pdata->clks[i].clock = clock;
457 }
458
459 for (i = 0; i < drv->pdata->gpios_num; i++) {
460 const char *name = drv->pdata->gpios[i].name;
461 int num = drv->pdata->gpios[i].num;
462
463 drv->pdata->gpios[i].is_owner = false;
464
465 pr_debug("%s: get gpio %s.", __func__, name);
466
467 ret = gpio_request(num, name);
468 if (ret) {
469 pr_err("%s: request GPIO %s err %d.",
470 __func__, name, ret);
471 goto gpio_err;
472 }
473
474 drv->pdata->gpios[i].is_owner = true;
475
476 }
477
478 for (i = 0; i < drv->pdata->regs_num; i++) {
479 const char *name = drv->pdata->regs[i].name;
480
481 drv->pdata->regs[i].reg = NULL;
482
483 pr_debug("%s: get regulator %s.", __func__, name);
484
485 drv->pdata->regs[i].reg = regulator_get(drv->dev, name);
486 if (IS_ERR(drv->pdata->regs[i].reg)) {
487 pr_err("%s: get regulator %s failed.",
488 __func__, name);
489 goto reg_err;
490 }
491 }
492
493 drv->ppss_base = ioremap(ppss_res->start,
494 resource_size(ppss_res));
495
Wentao Xua55500b2011-08-16 18:15:04 -0400496 ppss_wdog = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
497 "ppss_wdog");
498 if (ppss_wdog) {
499 ret = request_irq(ppss_wdog->start, dsps_wdog_bite_irq,
500 IRQF_TRIGGER_RISING, "dsps_wdog", NULL);
501 if (ret) {
502 pr_err("%s: request_irq fail %d\n", __func__, ret);
503 goto request_irq_err;
504 }
505 } else {
506 pr_debug("%s: ppss_wdog not supported.\n", __func__);
507 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700508 return 0;
509
Wentao Xua55500b2011-08-16 18:15:04 -0400510request_irq_err:
511 iounmap(drv->ppss_base);
512
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513reg_err:
514 for (i = 0; i < drv->pdata->regs_num; i++) {
515 if (drv->pdata->regs[i].reg) {
516 regulator_put(drv->pdata->regs[i].reg);
517 drv->pdata->regs[i].reg = NULL;
518 }
519 }
520
521gpio_err:
522 for (i = 0; i < drv->pdata->gpios_num; i++)
523 if (drv->pdata->gpios[i].is_owner) {
524 gpio_free(drv->pdata->gpios[i].num);
525 drv->pdata->gpios[i].is_owner = false;
526 }
527clk_err:
528 for (i = 0; i < drv->pdata->clks_num; i++)
529 if (drv->pdata->clks[i].clock) {
530 clk_put(drv->pdata->clks[i].clock);
531 drv->pdata->clks[i].clock = NULL;
532 }
533
534 return ret;
535}
536
537/**
538 * Open File.
539 *
540 */
541static int dsps_open(struct inode *ip, struct file *fp)
542{
543 int ret = 0;
544
545 pr_debug("%s.\n", __func__);
546
547 if (drv->ref_count == 0) {
548
549 /* clocks must be ON before loading.*/
550 ret = dsps_power_on_handler();
551 if (ret)
552 return ret;
553
554 ret = dsps_load(drv->pdata->pil_name);
555
556 if (ret) {
557 dsps_power_off_handler();
558 return ret;
559 }
560
561 dsps_resume();
562 }
563 drv->ref_count++;
564
565 return ret;
566}
567
568/**
569 * free resources.
570 *
571 */
572static void dsps_free_resources(void)
573{
574 int i;
575
576 pr_debug("%s.\n", __func__);
577
578 for (i = 0; i < drv->pdata->clks_num; i++)
579 if (drv->pdata->clks[i].clock) {
580 clk_put(drv->pdata->clks[i].clock);
581 drv->pdata->clks[i].clock = NULL;
582 }
583
584 for (i = 0; i < drv->pdata->gpios_num; i++)
585 if (drv->pdata->gpios[i].is_owner) {
586 gpio_free(drv->pdata->gpios[i].num);
587 drv->pdata->gpios[i].is_owner = false;
588 }
589
590 for (i = 0; i < drv->pdata->regs_num; i++) {
591 if (drv->pdata->regs[i].reg) {
592 regulator_put(drv->pdata->regs[i].reg);
593 drv->pdata->regs[i].reg = NULL;
594 }
595 }
596
597 iounmap(drv->ppss_base);
598}
599
600/**
601 * Close File.
602 *
603 * The client shall close and re-open the file for re-loading the DSPS
604 * firmware.
605 * The file system will close the file if the user space app has crashed.
606 *
607 * If the DSPS is running, then we must reset DSPS CPU & HW before
608 * setting the clocks off.
609 * The DSPS reset should be done as part of the pil_put().
610 * The DSPS reset should be used for error recovery if the DSPS firmware
611 * has crashed and re-loading the firmware is required.
612 */
613static int dsps_release(struct inode *inode, struct file *file)
614{
615 pr_debug("%s.\n", __func__);
616
617 drv->ref_count--;
618
619 if (drv->ref_count == 0) {
620 if (!drv->pdata->dsps_pwr_ctl_en) {
621 dsps_suspend();
622
623 dsps_unload();
624
625 dsps_power_off_handler();
626 }
627 }
628
629 return 0;
630}
631
632const struct file_operations dsps_fops = {
633 .owner = THIS_MODULE,
634 .open = dsps_open,
635 .release = dsps_release,
636 .unlocked_ioctl = dsps_ioctl,
637};
638
639/**
Wentao Xua55500b2011-08-16 18:15:04 -0400640 * Fatal error handler
641 * Resets DSPS.
642 */
643static void dsps_fatal_handler(struct work_struct *work)
644{
645 uint32_t dsps_state;
646
647 dsps_state = smsm_get_state(SMSM_DSPS_STATE);
648
649 pr_debug("%s: DSPS state 0x%x\n", __func__, dsps_state);
650
651 if (dsps_state & SMSM_RESET) {
652 pr_err("%s: DSPS fatal error detected. Resetting\n",
653 __func__);
654 } else {
655 pr_debug("%s: User-initiated DSPS reset. Resetting\n",
656 __func__);
657 }
658 subsystem_restart("dsps");
659}
660
661
662/**
663 * SMSM state change callback
664 *
665 */
666static void dsps_smsm_state_cb(void *data, uint32_t old_state,
667 uint32_t new_state)
668{
669 pr_debug("%s\n", __func__);
670 if (dsps_crash_shutdown_g == 1) {
671 pr_debug("%s: SMSM_RESET state change ignored\n",
672 __func__);
673 dsps_crash_shutdown_g = 0;
674 return;
675 }
676
677 if (new_state & SMSM_RESET) {
678 pr_err
679 ("%s: SMSM_RESET state detected. restarting the DSPS\n",
680 __func__);
681 subsystem_restart("dsps");
682 }
683}
684
685/**
686 * Shutdown function
687 * called by the restart notifier
688 *
689 */
690static int dsps_shutdown(const struct subsys_data *subsys)
691{
692 pr_debug("%s\n", __func__);
693 dsps_unload();
694 return 0;
695}
696
697/**
698 * Powerup function
699 * called by the restart notifier
700 *
701 */
702static int dsps_powerup(const struct subsys_data *subsys)
703{
704 pr_debug("%s\n", __func__);
705 if (dsps_load(drv->pdata->pil_name) != 0) {
706 pr_err("%s: fail to restart DSPS after reboot\n",
707 __func__);
708 return 1;
709 }
710 return 0;
711}
712
713/**
714 * Crash shutdown function
715 * called by the restart notifier
716 *
717 */
718static void dsps_crash_shutdown(const struct subsys_data *subsys)
719{
720 pr_debug("%s\n", __func__);
721 dsps_crash_shutdown_g = 1;
722 smsm_change_state(SMSM_DSPS_STATE, SMSM_RESET, SMSM_RESET);
723}
724
725/**
726 * Ramdump function
727 * called by the restart notifier
728 *
729 */
730static int dsps_ramdump(int enable, const struct subsys_data *subsys)
731{
732 pr_debug("%s\n", __func__);
733 return 0;
734}
735
736static struct subsys_data dsps_ssrops = {
737 .name = "dsps",
738 .shutdown = dsps_shutdown,
739 .powerup = dsps_powerup,
740 .ramdump = dsps_ramdump,
741 .crash_shutdown = dsps_crash_shutdown
742};
743
744/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700745 * platform driver
746 *
747 */
748static int __devinit dsps_probe(struct platform_device *pdev)
749{
750 int ret;
751
752 pr_debug("%s.\n", __func__);
753
754 if (pdev->dev.platform_data == NULL) {
755 pr_err("%s: platform data is NULL.\n", __func__);
756 return -ENODEV;
757 }
758
759 drv = kzalloc(sizeof(*drv), GFP_KERNEL);
760 if (drv == NULL) {
761 pr_err("%s: kzalloc fail.\n", __func__);
762 goto alloc_err;
763 }
764 drv->pdata = pdev->dev.platform_data;
765
766 ret = dsps_alloc_resources(pdev);
767 if (ret) {
768 pr_err("%s: failed to allocate dsps resources.\n", __func__);
769 goto res_err;
770 }
771
772 drv->dev_class = class_create(THIS_MODULE, DRV_NAME);
773 if (drv->dev_class == NULL) {
774 pr_err("%s: class_create fail.\n", __func__);
775 goto res_err;
776 }
777
778 ret = alloc_chrdev_region(&drv->dev_num, 0, 1, DRV_NAME);
779 if (ret) {
780 pr_err("%s: alloc_chrdev_region fail.\n", __func__);
781 goto alloc_chrdev_region_err;
782 }
783
784 drv->dev = device_create(drv->dev_class, NULL,
785 drv->dev_num,
786 drv, DRV_NAME);
787 if (IS_ERR(drv->dev)) {
788 pr_err("%s: device_create fail.\n", __func__);
789 goto device_create_err;
790 }
791
792 drv->cdev = cdev_alloc();
793 if (drv->cdev == NULL) {
794 pr_err("%s: cdev_alloc fail.\n", __func__);
795 goto cdev_alloc_err;
796 }
797 cdev_init(drv->cdev, &dsps_fops);
798 drv->cdev->owner = THIS_MODULE;
799
800 ret = cdev_add(drv->cdev, drv->dev_num, 1);
801 if (ret) {
802 pr_err("%s: cdev_add fail.\n", __func__);
803 goto cdev_add_err;
804 }
805
Wentao Xua55500b2011-08-16 18:15:04 -0400806 ret =
807 smsm_state_cb_register(SMSM_DSPS_STATE, SMSM_RESET,
808 dsps_smsm_state_cb, 0);
809 if (ret) {
810 pr_err("%s: smsm_state_cb_register fail %d\n", __func__,
811 ret);
812 goto smsm_register_err;
813 }
814
815 ret = ssr_register_subsystem(&dsps_ssrops);
816 if (ret) {
817 pr_err("%s: ssr_register_subsystem fail %d\n", __func__,
818 ret);
819 goto ssr_register_err;
820 }
821
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700822 return 0;
823
Wentao Xua55500b2011-08-16 18:15:04 -0400824ssr_register_err:
825 smsm_state_cb_deregister(SMSM_DSPS_STATE, SMSM_RESET,
826 dsps_smsm_state_cb,
827 0);
828smsm_register_err:
829 cdev_del(drv->cdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700830cdev_add_err:
831 kfree(drv->cdev);
832cdev_alloc_err:
833 device_destroy(drv->dev_class, drv->dev_num);
834device_create_err:
835 unregister_chrdev_region(drv->dev_num, 1);
836alloc_chrdev_region_err:
837 class_destroy(drv->dev_class);
838res_err:
839 kfree(drv);
840 drv = NULL;
841alloc_err:
842 return -ENODEV;
843}
844
845static int __devexit dsps_remove(struct platform_device *pdev)
846{
847 pr_debug("%s.\n", __func__);
848
849 dsps_power_off_handler();
850 dsps_free_resources();
851
852 cdev_del(drv->cdev);
853 kfree(drv->cdev);
854 drv->cdev = NULL;
855 device_destroy(drv->dev_class, drv->dev_num);
856 unregister_chrdev_region(drv->dev_num, 1);
857 class_destroy(drv->dev_class);
858 kfree(drv);
859 drv = NULL;
860
861 return 0;
862}
863
864static struct platform_driver dsps_driver = {
865 .probe = dsps_probe,
866 .remove = __exit_p(dsps_remove),
867 .driver = {
868 .name = "msm_dsps",
869 },
870};
871
872/**
873 * Module Init.
874 */
875static int __init dsps_init(void)
876{
877 int ret;
878
879 pr_info("%s driver version %s.\n", DRV_NAME, DRV_VERSION);
880
881 ret = platform_driver_register(&dsps_driver);
882
883 if (ret)
884 pr_err("dsps_init.err=%d.\n", ret);
885
886 return ret;
887}
888
889/**
890 * Module Exit.
891 */
892static void __exit dsps_exit(void)
893{
894 pr_debug("%s.\n", __func__);
895
896 platform_driver_unregister(&dsps_driver);
897}
898
899module_init(dsps_init);
900module_exit(dsps_exit);
901
902MODULE_LICENSE("GPL v2");
903MODULE_DESCRIPTION("Dedicated Sensors Processor Subsystem (DSPS) driver");
904MODULE_AUTHOR("Amir Samuelov <amirs@codeaurora.org>");
905