blob: 4e487a7f933a1198dc692c894a66ab1e7243933e [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"
Terence Hampson49f6ca62011-12-01 10:38:18 -050043#define DRV_VERSION "3.01"
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 }
Vidyakumar Athota439ee1e2011-12-25 20:58:49 -0800106 msleep(20);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700107 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__);
Terence Hampson49f6ca62011-12-01 10:38:18 -0500658 panic("DSPS fatal error detected.");
Wentao Xua55500b2011-08-16 18:15:04 -0400659 } else {
660 pr_debug("%s: User-initiated DSPS reset. Resetting\n",
661 __func__);
Terence Hampson49f6ca62011-12-01 10:38:18 -0500662 panic("User-initiated DSPS reset.");
Wentao Xua55500b2011-08-16 18:15:04 -0400663 }
Wentao Xua55500b2011-08-16 18:15:04 -0400664}
665
666
667/**
668 * SMSM state change callback
669 *
670 */
671static void dsps_smsm_state_cb(void *data, uint32_t old_state,
672 uint32_t new_state)
673{
674 pr_debug("%s\n", __func__);
675 if (dsps_crash_shutdown_g == 1) {
676 pr_debug("%s: SMSM_RESET state change ignored\n",
677 __func__);
678 dsps_crash_shutdown_g = 0;
679 return;
680 }
681
682 if (new_state & SMSM_RESET) {
683 pr_err
684 ("%s: SMSM_RESET state detected. restarting the DSPS\n",
685 __func__);
Terence Hampson49f6ca62011-12-01 10:38:18 -0500686 panic("SMSM_RESET state detected.");
Wentao Xua55500b2011-08-16 18:15:04 -0400687 }
688}
689
690/**
691 * Shutdown function
692 * called by the restart notifier
693 *
694 */
695static int dsps_shutdown(const struct subsys_data *subsys)
696{
697 pr_debug("%s\n", __func__);
698 dsps_unload();
699 return 0;
700}
701
702/**
703 * Powerup function
704 * called by the restart notifier
705 *
706 */
707static int dsps_powerup(const struct subsys_data *subsys)
708{
709 pr_debug("%s\n", __func__);
710 if (dsps_load(drv->pdata->pil_name) != 0) {
711 pr_err("%s: fail to restart DSPS after reboot\n",
712 __func__);
713 return 1;
714 }
715 return 0;
716}
717
718/**
719 * Crash shutdown function
720 * called by the restart notifier
721 *
722 */
723static void dsps_crash_shutdown(const struct subsys_data *subsys)
724{
725 pr_debug("%s\n", __func__);
726 dsps_crash_shutdown_g = 1;
727 smsm_change_state(SMSM_DSPS_STATE, SMSM_RESET, SMSM_RESET);
728}
729
730/**
731 * Ramdump function
732 * called by the restart notifier
733 *
734 */
735static int dsps_ramdump(int enable, const struct subsys_data *subsys)
736{
737 pr_debug("%s\n", __func__);
738 return 0;
739}
740
741static struct subsys_data dsps_ssrops = {
742 .name = "dsps",
743 .shutdown = dsps_shutdown,
744 .powerup = dsps_powerup,
745 .ramdump = dsps_ramdump,
746 .crash_shutdown = dsps_crash_shutdown
747};
748
749/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700750 * platform driver
751 *
752 */
753static int __devinit dsps_probe(struct platform_device *pdev)
754{
755 int ret;
756
757 pr_debug("%s.\n", __func__);
758
759 if (pdev->dev.platform_data == NULL) {
760 pr_err("%s: platform data is NULL.\n", __func__);
761 return -ENODEV;
762 }
763
764 drv = kzalloc(sizeof(*drv), GFP_KERNEL);
765 if (drv == NULL) {
766 pr_err("%s: kzalloc fail.\n", __func__);
767 goto alloc_err;
768 }
769 drv->pdata = pdev->dev.platform_data;
770
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700771 drv->dev_class = class_create(THIS_MODULE, DRV_NAME);
772 if (drv->dev_class == NULL) {
773 pr_err("%s: class_create fail.\n", __func__);
774 goto res_err;
775 }
776
777 ret = alloc_chrdev_region(&drv->dev_num, 0, 1, DRV_NAME);
778 if (ret) {
779 pr_err("%s: alloc_chrdev_region fail.\n", __func__);
780 goto alloc_chrdev_region_err;
781 }
782
783 drv->dev = device_create(drv->dev_class, NULL,
784 drv->dev_num,
785 drv, DRV_NAME);
786 if (IS_ERR(drv->dev)) {
787 pr_err("%s: device_create fail.\n", __func__);
788 goto device_create_err;
789 }
790
791 drv->cdev = cdev_alloc();
792 if (drv->cdev == NULL) {
793 pr_err("%s: cdev_alloc fail.\n", __func__);
794 goto cdev_alloc_err;
795 }
796 cdev_init(drv->cdev, &dsps_fops);
797 drv->cdev->owner = THIS_MODULE;
798
799 ret = cdev_add(drv->cdev, drv->dev_num, 1);
800 if (ret) {
801 pr_err("%s: cdev_add fail.\n", __func__);
802 goto cdev_add_err;
803 }
804
Wentao Xu4a053042011-10-03 14:06:34 -0400805 ret = dsps_alloc_resources(pdev);
806 if (ret) {
807 pr_err("%s: failed to allocate dsps resources.\n", __func__);
808 goto cdev_add_err;
809 }
810
Wentao Xua55500b2011-08-16 18:15:04 -0400811 ret =
812 smsm_state_cb_register(SMSM_DSPS_STATE, SMSM_RESET,
813 dsps_smsm_state_cb, 0);
814 if (ret) {
815 pr_err("%s: smsm_state_cb_register fail %d\n", __func__,
816 ret);
817 goto smsm_register_err;
818 }
819
820 ret = ssr_register_subsystem(&dsps_ssrops);
821 if (ret) {
822 pr_err("%s: ssr_register_subsystem fail %d\n", __func__,
823 ret);
824 goto ssr_register_err;
825 }
826
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700827 return 0;
828
Wentao Xua55500b2011-08-16 18:15:04 -0400829ssr_register_err:
830 smsm_state_cb_deregister(SMSM_DSPS_STATE, SMSM_RESET,
831 dsps_smsm_state_cb,
832 0);
833smsm_register_err:
834 cdev_del(drv->cdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700835cdev_add_err:
836 kfree(drv->cdev);
837cdev_alloc_err:
838 device_destroy(drv->dev_class, drv->dev_num);
839device_create_err:
840 unregister_chrdev_region(drv->dev_num, 1);
841alloc_chrdev_region_err:
842 class_destroy(drv->dev_class);
843res_err:
844 kfree(drv);
845 drv = NULL;
846alloc_err:
847 return -ENODEV;
848}
849
850static int __devexit dsps_remove(struct platform_device *pdev)
851{
852 pr_debug("%s.\n", __func__);
853
854 dsps_power_off_handler();
855 dsps_free_resources();
856
857 cdev_del(drv->cdev);
858 kfree(drv->cdev);
859 drv->cdev = NULL;
860 device_destroy(drv->dev_class, drv->dev_num);
861 unregister_chrdev_region(drv->dev_num, 1);
862 class_destroy(drv->dev_class);
863 kfree(drv);
864 drv = NULL;
865
866 return 0;
867}
868
869static struct platform_driver dsps_driver = {
870 .probe = dsps_probe,
871 .remove = __exit_p(dsps_remove),
872 .driver = {
873 .name = "msm_dsps",
874 },
875};
876
877/**
878 * Module Init.
879 */
880static int __init dsps_init(void)
881{
882 int ret;
883
884 pr_info("%s driver version %s.\n", DRV_NAME, DRV_VERSION);
885
886 ret = platform_driver_register(&dsps_driver);
887
888 if (ret)
889 pr_err("dsps_init.err=%d.\n", ret);
890
891 return ret;
892}
893
894/**
895 * Module Exit.
896 */
897static void __exit dsps_exit(void)
898{
899 pr_debug("%s.\n", __func__);
900
901 platform_driver_unregister(&dsps_driver);
902}
903
904module_init(dsps_init);
905module_exit(dsps_exit);
906
907MODULE_LICENSE("GPL v2");
908MODULE_DESCRIPTION("Dedicated Sensors Processor Subsystem (DSPS) driver");
909MODULE_AUTHOR("Amir Samuelov <amirs@codeaurora.org>");
910