blob: bcb777f3f1bbafa6cf83675f50b0bca6308efe40 [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 }
Wentao Xu7a1c9302011-09-19 17:57:43 -0400508
509 if (drv->pdata->init)
510 drv->pdata->init(drv->pdata);
511
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700512 return 0;
513
Wentao Xua55500b2011-08-16 18:15:04 -0400514request_irq_err:
515 iounmap(drv->ppss_base);
516
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700517reg_err:
518 for (i = 0; i < drv->pdata->regs_num; i++) {
519 if (drv->pdata->regs[i].reg) {
520 regulator_put(drv->pdata->regs[i].reg);
521 drv->pdata->regs[i].reg = NULL;
522 }
523 }
524
525gpio_err:
526 for (i = 0; i < drv->pdata->gpios_num; i++)
527 if (drv->pdata->gpios[i].is_owner) {
528 gpio_free(drv->pdata->gpios[i].num);
529 drv->pdata->gpios[i].is_owner = false;
530 }
531clk_err:
532 for (i = 0; i < drv->pdata->clks_num; i++)
533 if (drv->pdata->clks[i].clock) {
534 clk_put(drv->pdata->clks[i].clock);
535 drv->pdata->clks[i].clock = NULL;
536 }
537
538 return ret;
539}
540
541/**
542 * Open File.
543 *
544 */
545static int dsps_open(struct inode *ip, struct file *fp)
546{
547 int ret = 0;
548
549 pr_debug("%s.\n", __func__);
550
551 if (drv->ref_count == 0) {
552
553 /* clocks must be ON before loading.*/
554 ret = dsps_power_on_handler();
555 if (ret)
556 return ret;
557
558 ret = dsps_load(drv->pdata->pil_name);
559
560 if (ret) {
561 dsps_power_off_handler();
562 return ret;
563 }
564
565 dsps_resume();
566 }
567 drv->ref_count++;
568
569 return ret;
570}
571
572/**
573 * free resources.
574 *
575 */
576static void dsps_free_resources(void)
577{
578 int i;
579
580 pr_debug("%s.\n", __func__);
581
582 for (i = 0; i < drv->pdata->clks_num; i++)
583 if (drv->pdata->clks[i].clock) {
584 clk_put(drv->pdata->clks[i].clock);
585 drv->pdata->clks[i].clock = NULL;
586 }
587
588 for (i = 0; i < drv->pdata->gpios_num; i++)
589 if (drv->pdata->gpios[i].is_owner) {
590 gpio_free(drv->pdata->gpios[i].num);
591 drv->pdata->gpios[i].is_owner = false;
592 }
593
594 for (i = 0; i < drv->pdata->regs_num; i++) {
595 if (drv->pdata->regs[i].reg) {
596 regulator_put(drv->pdata->regs[i].reg);
597 drv->pdata->regs[i].reg = NULL;
598 }
599 }
600
601 iounmap(drv->ppss_base);
602}
603
604/**
605 * Close File.
606 *
607 * The client shall close and re-open the file for re-loading the DSPS
608 * firmware.
609 * The file system will close the file if the user space app has crashed.
610 *
611 * If the DSPS is running, then we must reset DSPS CPU & HW before
612 * setting the clocks off.
613 * The DSPS reset should be done as part of the pil_put().
614 * The DSPS reset should be used for error recovery if the DSPS firmware
615 * has crashed and re-loading the firmware is required.
616 */
617static int dsps_release(struct inode *inode, struct file *file)
618{
619 pr_debug("%s.\n", __func__);
620
621 drv->ref_count--;
622
623 if (drv->ref_count == 0) {
624 if (!drv->pdata->dsps_pwr_ctl_en) {
625 dsps_suspend();
626
627 dsps_unload();
628
629 dsps_power_off_handler();
630 }
631 }
632
633 return 0;
634}
635
636const struct file_operations dsps_fops = {
637 .owner = THIS_MODULE,
638 .open = dsps_open,
639 .release = dsps_release,
640 .unlocked_ioctl = dsps_ioctl,
641};
642
643/**
Wentao Xua55500b2011-08-16 18:15:04 -0400644 * Fatal error handler
645 * Resets DSPS.
646 */
647static void dsps_fatal_handler(struct work_struct *work)
648{
649 uint32_t dsps_state;
650
651 dsps_state = smsm_get_state(SMSM_DSPS_STATE);
652
653 pr_debug("%s: DSPS state 0x%x\n", __func__, dsps_state);
654
655 if (dsps_state & SMSM_RESET) {
656 pr_err("%s: DSPS fatal error detected. Resetting\n",
657 __func__);
658 } else {
659 pr_debug("%s: User-initiated DSPS reset. Resetting\n",
660 __func__);
661 }
662 subsystem_restart("dsps");
663}
664
665
666/**
667 * SMSM state change callback
668 *
669 */
670static void dsps_smsm_state_cb(void *data, uint32_t old_state,
671 uint32_t new_state)
672{
673 pr_debug("%s\n", __func__);
674 if (dsps_crash_shutdown_g == 1) {
675 pr_debug("%s: SMSM_RESET state change ignored\n",
676 __func__);
677 dsps_crash_shutdown_g = 0;
678 return;
679 }
680
681 if (new_state & SMSM_RESET) {
682 pr_err
683 ("%s: SMSM_RESET state detected. restarting the DSPS\n",
684 __func__);
685 subsystem_restart("dsps");
686 }
687}
688
689/**
690 * Shutdown function
691 * called by the restart notifier
692 *
693 */
694static int dsps_shutdown(const struct subsys_data *subsys)
695{
696 pr_debug("%s\n", __func__);
697 dsps_unload();
698 return 0;
699}
700
701/**
702 * Powerup function
703 * called by the restart notifier
704 *
705 */
706static int dsps_powerup(const struct subsys_data *subsys)
707{
708 pr_debug("%s\n", __func__);
709 if (dsps_load(drv->pdata->pil_name) != 0) {
710 pr_err("%s: fail to restart DSPS after reboot\n",
711 __func__);
712 return 1;
713 }
714 return 0;
715}
716
717/**
718 * Crash shutdown function
719 * called by the restart notifier
720 *
721 */
722static void dsps_crash_shutdown(const struct subsys_data *subsys)
723{
724 pr_debug("%s\n", __func__);
725 dsps_crash_shutdown_g = 1;
726 smsm_change_state(SMSM_DSPS_STATE, SMSM_RESET, SMSM_RESET);
727}
728
729/**
730 * Ramdump function
731 * called by the restart notifier
732 *
733 */
734static int dsps_ramdump(int enable, const struct subsys_data *subsys)
735{
736 pr_debug("%s\n", __func__);
737 return 0;
738}
739
740static struct subsys_data dsps_ssrops = {
741 .name = "dsps",
742 .shutdown = dsps_shutdown,
743 .powerup = dsps_powerup,
744 .ramdump = dsps_ramdump,
745 .crash_shutdown = dsps_crash_shutdown
746};
747
748/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700749 * platform driver
750 *
751 */
752static int __devinit dsps_probe(struct platform_device *pdev)
753{
754 int ret;
755
756 pr_debug("%s.\n", __func__);
757
758 if (pdev->dev.platform_data == NULL) {
759 pr_err("%s: platform data is NULL.\n", __func__);
760 return -ENODEV;
761 }
762
763 drv = kzalloc(sizeof(*drv), GFP_KERNEL);
764 if (drv == NULL) {
765 pr_err("%s: kzalloc fail.\n", __func__);
766 goto alloc_err;
767 }
768 drv->pdata = pdev->dev.platform_data;
769
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700770 drv->dev_class = class_create(THIS_MODULE, DRV_NAME);
771 if (drv->dev_class == NULL) {
772 pr_err("%s: class_create fail.\n", __func__);
773 goto res_err;
774 }
775
776 ret = alloc_chrdev_region(&drv->dev_num, 0, 1, DRV_NAME);
777 if (ret) {
778 pr_err("%s: alloc_chrdev_region fail.\n", __func__);
779 goto alloc_chrdev_region_err;
780 }
781
782 drv->dev = device_create(drv->dev_class, NULL,
783 drv->dev_num,
784 drv, DRV_NAME);
785 if (IS_ERR(drv->dev)) {
786 pr_err("%s: device_create fail.\n", __func__);
787 goto device_create_err;
788 }
789
790 drv->cdev = cdev_alloc();
791 if (drv->cdev == NULL) {
792 pr_err("%s: cdev_alloc fail.\n", __func__);
793 goto cdev_alloc_err;
794 }
795 cdev_init(drv->cdev, &dsps_fops);
796 drv->cdev->owner = THIS_MODULE;
797
798 ret = cdev_add(drv->cdev, drv->dev_num, 1);
799 if (ret) {
800 pr_err("%s: cdev_add fail.\n", __func__);
801 goto cdev_add_err;
802 }
803
Wentao Xu4a053042011-10-03 14:06:34 -0400804 ret = dsps_alloc_resources(pdev);
805 if (ret) {
806 pr_err("%s: failed to allocate dsps resources.\n", __func__);
807 goto cdev_add_err;
808 }
809
Wentao Xua55500b2011-08-16 18:15:04 -0400810 ret =
811 smsm_state_cb_register(SMSM_DSPS_STATE, SMSM_RESET,
812 dsps_smsm_state_cb, 0);
813 if (ret) {
814 pr_err("%s: smsm_state_cb_register fail %d\n", __func__,
815 ret);
816 goto smsm_register_err;
817 }
818
819 ret = ssr_register_subsystem(&dsps_ssrops);
820 if (ret) {
821 pr_err("%s: ssr_register_subsystem fail %d\n", __func__,
822 ret);
823 goto ssr_register_err;
824 }
825
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700826 return 0;
827
Wentao Xua55500b2011-08-16 18:15:04 -0400828ssr_register_err:
829 smsm_state_cb_deregister(SMSM_DSPS_STATE, SMSM_RESET,
830 dsps_smsm_state_cb,
831 0);
832smsm_register_err:
833 cdev_del(drv->cdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700834cdev_add_err:
835 kfree(drv->cdev);
836cdev_alloc_err:
837 device_destroy(drv->dev_class, drv->dev_num);
838device_create_err:
839 unregister_chrdev_region(drv->dev_num, 1);
840alloc_chrdev_region_err:
841 class_destroy(drv->dev_class);
842res_err:
843 kfree(drv);
844 drv = NULL;
845alloc_err:
846 return -ENODEV;
847}
848
849static int __devexit dsps_remove(struct platform_device *pdev)
850{
851 pr_debug("%s.\n", __func__);
852
853 dsps_power_off_handler();
854 dsps_free_resources();
855
856 cdev_del(drv->cdev);
857 kfree(drv->cdev);
858 drv->cdev = NULL;
859 device_destroy(drv->dev_class, drv->dev_num);
860 unregister_chrdev_region(drv->dev_num, 1);
861 class_destroy(drv->dev_class);
862 kfree(drv);
863 drv = NULL;
864
865 return 0;
866}
867
868static struct platform_driver dsps_driver = {
869 .probe = dsps_probe,
870 .remove = __exit_p(dsps_remove),
871 .driver = {
872 .name = "msm_dsps",
873 },
874};
875
876/**
877 * Module Init.
878 */
879static int __init dsps_init(void)
880{
881 int ret;
882
883 pr_info("%s driver version %s.\n", DRV_NAME, DRV_VERSION);
884
885 ret = platform_driver_register(&dsps_driver);
886
887 if (ret)
888 pr_err("dsps_init.err=%d.\n", ret);
889
890 return ret;
891}
892
893/**
894 * Module Exit.
895 */
896static void __exit dsps_exit(void)
897{
898 pr_debug("%s.\n", __func__);
899
900 platform_driver_unregister(&dsps_driver);
901}
902
903module_init(dsps_init);
904module_exit(dsps_exit);
905
906MODULE_LICENSE("GPL v2");
907MODULE_DESCRIPTION("Dedicated Sensors Processor Subsystem (DSPS) driver");
908MODULE_AUTHOR("Amir Samuelov <amirs@codeaurora.org>");
909