blob: 55982f33474bf3fab64aa61b5e357f8292e3b770 [file] [log] [blame]
Laxminath Kasam468ece32017-11-28 12:40:22 +05301/* Copyright (c) 2013-2014, 2017-2018 The Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302 *
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#include <linux/init.h>
14#include <linux/module.h>
15#include <linux/fs.h>
16#include <linux/device.h>
17#include <linux/mutex.h>
18#include <linux/miscdevice.h>
19#include <sound/audio_slimslave.h>
20#include <linux/slimbus/slimbus.h>
21#include <linux/pm_runtime.h>
22
23static struct slim_device *slim;
24static int vote_count;
25struct mutex suspend_lock;
26bool suspend;
27
28static int audio_slim_open(struct inode *inode, struct file *file)
29{
30 pr_debug("%s:\n", __func__);
31
32 if (vote_count) {
33 pr_debug("%s: unvote: vote_count=%d\n", __func__, vote_count);
34 pm_runtime_mark_last_busy(slim->dev.parent);
35 pm_runtime_put(slim->dev.parent);
36 vote_count--;
37 }
38 return 0;
39};
40
41static int audio_slim_release(struct inode *inode, struct file *file)
42{
43 pr_debug("%s:\n", __func__);
44
45 if (vote_count) {
46 pr_debug("%s: unvote: vote_count=%d\n", __func__, vote_count);
47 pm_runtime_mark_last_busy(slim->dev.parent);
48 pm_runtime_put(slim->dev.parent);
49 vote_count--;
50 } else {
51 pr_debug("%s: vote: vote_count=%d\n", __func__, vote_count);
52 pm_runtime_get_sync(slim->dev.parent);
53 vote_count++;
54 }
55 return 0;
56};
57
58static long audio_slim_ioctl(struct file *file, unsigned int cmd,
59 unsigned long u_arg)
60{
61 switch (cmd) {
62 case AUDIO_SLIMSLAVE_VOTE:
63 mutex_lock(&suspend_lock);
64 if (!vote_count && !suspend) {
65 pr_debug("%s:AUDIO_SLIMSLAVE_VOTE\n", __func__);
66 pm_runtime_get_sync(slim->dev.parent);
67 vote_count++;
68 } else {
69 pr_err("%s:Invalid vote: vote_count=%d suspend=%d\n",
70 __func__, vote_count, suspend);
71 }
72 mutex_unlock(&suspend_lock);
73 break;
74 case AUDIO_SLIMSLAVE_UNVOTE:
75 mutex_lock(&suspend_lock);
76 if (vote_count && !suspend) {
77 pr_debug("%s:AUDIO_SLIMSLAVE_UNVOTE\n", __func__);
78 pm_runtime_mark_last_busy(slim->dev.parent);
79 pm_runtime_put(slim->dev.parent);
80 vote_count--;
81 } else {
82 pr_err("%s:Invalid unvote: vote_count=%d suspend=%d\n",
83 __func__, vote_count, suspend);
84 }
85 mutex_unlock(&suspend_lock);
86 break;
87 default:
88 pr_debug("%s: Invalid ioctl cmd: %d\n", __func__, cmd);
89 break;
90 }
91 return 0;
92}
93
94static const struct file_operations audio_slimslave_fops = {
95 .open = audio_slim_open,
96 .unlocked_ioctl = audio_slim_ioctl,
97 .release = audio_slim_release,
98};
99
100struct miscdevice audio_slimslave_misc = {
101 .minor = MISC_DYNAMIC_MINOR,
102 .name = AUDIO_SLIMSLAVE_IOCTL_NAME,
103 .fops = &audio_slimslave_fops,
104};
105
106static int audio_slimslave_probe(struct slim_device *audio_slim)
107{
108 pr_debug("%s:\n", __func__);
109
110 mutex_init(&suspend_lock);
111 suspend = false;
112 slim = audio_slim;
113 misc_register(&audio_slimslave_misc);
114 return 0;
115}
116
117static int audio_slimslave_remove(struct slim_device *audio_slim)
118{
119 pr_debug("%s:\n", __func__);
120
121 misc_deregister(&audio_slimslave_misc);
122 return 0;
123}
124
125static int audio_slimslave_resume(struct slim_device *audio_slim)
126{
127 pr_debug("%s:\n", __func__);
128
129 mutex_lock(&suspend_lock);
130 suspend = false;
131 mutex_unlock(&suspend_lock);
132 return 0;
133}
134
135static int audio_slimslave_suspend(struct slim_device *audio_slim,
136 pm_message_t pmesg)
137{
138 pr_debug("%s:\n", __func__);
139
140 mutex_lock(&suspend_lock);
141 suspend = true;
142 mutex_unlock(&suspend_lock);
143 return 0;
144}
145
146static const struct slim_device_id audio_slimslave_dt_match[] = {
147 {"audio-slimslave", 0},
148 {}
149};
150
151static struct slim_driver audio_slimslave_driver = {
152 .driver = {
153 .name = "audio-slimslave",
154 .owner = THIS_MODULE,
155 },
156 .probe = audio_slimslave_probe,
157 .remove = audio_slimslave_remove,
158 .id_table = audio_slimslave_dt_match,
159 .resume = audio_slimslave_resume,
160 .suspend = audio_slimslave_suspend,
161};
162
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530163int __init audio_slimslave_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530164{
165 return slim_driver_register(&audio_slimslave_driver);
166}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530167
Asish Bhattacharya5faacb32017-12-04 17:23:15 +0530168void audio_slimslave_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530169{
Laxminath Kasam468ece32017-11-28 12:40:22 +0530170 slim_driver_unregister(&audio_slimslave_driver);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530171}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530172
173/* Module information */
174MODULE_DESCRIPTION("Audio side Slimbus slave driver");
175MODULE_LICENSE("GPL v2");