123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- /* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/delay.h>
- #include <linux/slab.h>
- #include <linux/wait.h>
- #include <linux/sched.h>
- #include <linux/mfd/wcd9xxx/core-resource.h>
- static enum wcd9xxx_intf_status wcd9xxx_intf = -1;
- int wcd9xxx_core_irq_init(
- struct wcd9xxx_core_resource *wcd9xxx_core_res)
- {
- int ret = 0;
- if (wcd9xxx_core_res->irq != 1) {
- ret = wcd9xxx_irq_init(wcd9xxx_core_res);
- if (ret)
- pr_err("IRQ initialization failed\n");
- }
- return ret;
- }
- EXPORT_SYMBOL(wcd9xxx_core_irq_init);
- int wcd9xxx_initialize_irq(
- struct wcd9xxx_core_resource *wcd9xxx_core_res,
- unsigned int irq,
- unsigned int irq_base)
- {
- wcd9xxx_core_res->irq = irq;
- wcd9xxx_core_res->irq_base = irq_base;
- return 0;
- }
- EXPORT_SYMBOL(wcd9xxx_initialize_irq);
- int wcd9xxx_core_res_init(
- struct wcd9xxx_core_resource *wcd9xxx_core_res,
- int num_irqs, int num_irq_regs,
- int (*codec_read)(struct wcd9xxx_core_resource*, unsigned short),
- int (*codec_write)(struct wcd9xxx_core_resource*, unsigned short, u8),
- int (*codec_bulk_read) (struct wcd9xxx_core_resource*, unsigned short,
- int, u8*),
- int (*codec_bulk_write) (struct wcd9xxx_core_resource*, unsigned short,
- int, u8*))
- {
- mutex_init(&wcd9xxx_core_res->pm_lock);
- wcd9xxx_core_res->wlock_holders = 0;
- wcd9xxx_core_res->pm_state = WCD9XXX_PM_SLEEPABLE;
- init_waitqueue_head(&wcd9xxx_core_res->pm_wq);
- pm_qos_add_request(&wcd9xxx_core_res->pm_qos_req,
- PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
- wcd9xxx_core_res->codec_reg_read = codec_read;
- wcd9xxx_core_res->codec_reg_write = codec_write;
- wcd9xxx_core_res->codec_bulk_read = codec_bulk_read;
- wcd9xxx_core_res->codec_bulk_write = codec_bulk_write;
- wcd9xxx_core_res->num_irqs = num_irqs;
- wcd9xxx_core_res->num_irq_regs = num_irq_regs;
- pr_info("%s: num_irqs = %d, num_irq_regs = %d\n",
- __func__, wcd9xxx_core_res->num_irqs,
- wcd9xxx_core_res->num_irq_regs);
- return 0;
- }
- EXPORT_SYMBOL(wcd9xxx_core_res_init);
- void wcd9xxx_core_res_deinit(struct wcd9xxx_core_resource *wcd9xxx_core_res)
- {
- pm_qos_remove_request(&wcd9xxx_core_res->pm_qos_req);
- mutex_destroy(&wcd9xxx_core_res->pm_lock);
- wcd9xxx_core_res->codec_reg_read = NULL;
- wcd9xxx_core_res->codec_reg_write = NULL;
- wcd9xxx_core_res->codec_bulk_read = NULL;
- }
- EXPORT_SYMBOL(wcd9xxx_core_res_deinit);
- enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(
- struct wcd9xxx_core_resource *wcd9xxx_core_res,
- enum wcd9xxx_pm_state o,
- enum wcd9xxx_pm_state n)
- {
- enum wcd9xxx_pm_state old;
- mutex_lock(&wcd9xxx_core_res->pm_lock);
- old = wcd9xxx_core_res->pm_state;
- if (old == o)
- wcd9xxx_core_res->pm_state = n;
- mutex_unlock(&wcd9xxx_core_res->pm_lock);
- return old;
- }
- EXPORT_SYMBOL(wcd9xxx_pm_cmpxchg);
- int wcd9xxx_core_res_suspend(
- struct wcd9xxx_core_resource *wcd9xxx_core_res,
- pm_message_t pmesg)
- {
- int ret = 0;
- pr_debug("%s: enter\n", __func__);
- /*
- * pm_qos_update_request() can be called after this suspend chain call
- * started. thus suspend can be called while lock is being held
- */
- mutex_lock(&wcd9xxx_core_res->pm_lock);
- if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_SLEEPABLE) {
- pr_debug("%s: suspending system, state %d, wlock %d\n",
- __func__, wcd9xxx_core_res->pm_state,
- wcd9xxx_core_res->wlock_holders);
- wcd9xxx_core_res->pm_state = WCD9XXX_PM_ASLEEP;
- } else if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_AWAKE) {
- /*
- * unlock to wait for pm_state == WCD9XXX_PM_SLEEPABLE
- * then set to WCD9XXX_PM_ASLEEP
- */
- pr_debug("%s: waiting to suspend system, state %d, wlock %d\n",
- __func__, wcd9xxx_core_res->pm_state,
- wcd9xxx_core_res->wlock_holders);
- mutex_unlock(&wcd9xxx_core_res->pm_lock);
- if (!(wait_event_timeout(wcd9xxx_core_res->pm_wq,
- wcd9xxx_pm_cmpxchg(wcd9xxx_core_res,
- WCD9XXX_PM_SLEEPABLE,
- WCD9XXX_PM_ASLEEP) ==
- WCD9XXX_PM_SLEEPABLE,
- HZ))) {
- pr_debug("%s: suspend failed state %d, wlock %d\n",
- __func__, wcd9xxx_core_res->pm_state,
- wcd9xxx_core_res->wlock_holders);
- ret = -EBUSY;
- } else {
- pr_debug("%s: done, state %d, wlock %d\n", __func__,
- wcd9xxx_core_res->pm_state,
- wcd9xxx_core_res->wlock_holders);
- }
- mutex_lock(&wcd9xxx_core_res->pm_lock);
- } else if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_ASLEEP) {
- pr_warn("%s: system is already suspended, state %d, wlock %dn",
- __func__, wcd9xxx_core_res->pm_state,
- wcd9xxx_core_res->wlock_holders);
- }
- mutex_unlock(&wcd9xxx_core_res->pm_lock);
- return ret;
- }
- EXPORT_SYMBOL(wcd9xxx_core_res_suspend);
- int wcd9xxx_core_res_resume(
- struct wcd9xxx_core_resource *wcd9xxx_core_res)
- {
- int ret = 0;
- pr_debug("%s: enter\n", __func__);
- mutex_lock(&wcd9xxx_core_res->pm_lock);
- if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_ASLEEP) {
- pr_debug("%s: resuming system, state %d, wlock %d\n", __func__,
- wcd9xxx_core_res->pm_state,
- wcd9xxx_core_res->wlock_holders);
- wcd9xxx_core_res->pm_state = WCD9XXX_PM_SLEEPABLE;
- } else {
- pr_warn("%s: system is already awake, state %d wlock %d\n",
- __func__, wcd9xxx_core_res->pm_state,
- wcd9xxx_core_res->wlock_holders);
- }
- mutex_unlock(&wcd9xxx_core_res->pm_lock);
- wake_up_all(&wcd9xxx_core_res->pm_wq);
- return ret;
- }
- EXPORT_SYMBOL(wcd9xxx_core_res_resume);
- enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void)
- {
- return wcd9xxx_intf;
- }
- EXPORT_SYMBOL(wcd9xxx_get_intf_type);
- void wcd9xxx_set_intf_type(enum wcd9xxx_intf_status intf_status)
- {
- wcd9xxx_intf = intf_status;
- }
- EXPORT_SYMBOL(wcd9xxx_set_intf_type);
|