Merge tag 'lsk-v3.10-android-15.01'
[firefly-linux-kernel-4.4.55.git] / sound / soc / codecs / rt_codec_ioctl.c
1 /*
2  * rt_codec_ioctl.h  --  RT56XX ALSA SoC audio driver IO control
3  *
4  * Copyright 2012 Realtek Microelectronics
5  * Author: Bard <bardliao@realtek.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11
12 #include <linux/spi/spi.h>
13 #include <sound/soc.h>
14 #include "rt_codec_ioctl.h"
15
16 static struct rt_codec_ops rt_codec_ioctl_ops;
17
18 #if defined(CONFIG_SND_HWDEP) || defined(CONFIG_SND_HWDEP_MODULE)
19 #define RT_CE_CODEC_HWDEP_NAME "rt_codec hwdep "
20 static int rt_codec_hwdep_open(struct snd_hwdep *hw, struct file *file)
21 {
22         struct snd_soc_codec *codec = hw->private_data;
23         dev_dbg(codec->dev, "%s()\n", __func__);
24         return 0;
25 }
26
27 static int rt_codec_hwdep_release(struct snd_hwdep *hw, struct file *file)
28 {
29         struct snd_soc_codec *codec = hw->private_data;
30         dev_dbg(codec->dev, "%s()\n", __func__);
31         return 0;
32 }
33
34 static int rt_codec_hwdep_ioctl_common(struct snd_hwdep *hw,
35                 struct file *file, unsigned int cmd, unsigned long arg)
36 {
37         struct snd_soc_codec *codec = hw->private_data;
38         struct rt_codec_cmd __user *_rt_codec = (struct rt_codec_cmd *)arg;
39         struct rt_codec_cmd rt_codec;
40         int *buf, *p;
41
42         if (copy_from_user(&rt_codec, _rt_codec, sizeof(rt_codec))) {
43                 dev_err(codec->dev,"copy_from_user faild\n");
44                 return -EFAULT;
45         }
46         dev_dbg(codec->dev, "%s(): rt_codec.number=%zu, cmd=%d\n",
47                 __func__, rt_codec.number, cmd);
48         buf = kmalloc(sizeof(*buf) * rt_codec.number, GFP_KERNEL);
49         if (buf == NULL)
50                 return -ENOMEM;
51         if (copy_from_user(buf, rt_codec.buf, sizeof(*buf) * rt_codec.number)) {
52                 goto err;
53         }
54         
55         switch (cmd) {
56         case RT_READ_CODEC_REG_IOCTL:
57                 for (p = buf; p < buf + rt_codec.number / 2; p++) {
58                         *(p + rt_codec.number / 2) = snd_soc_read(codec, *p);
59                 }
60                 if (copy_to_user(rt_codec.buf, buf, sizeof(*buf) * rt_codec.number))
61                         goto err;
62                 break;          
63
64         case RT_WRITE_CODEC_REG_IOCTL:
65                 for (p = buf; p < buf + rt_codec.number / 2; p++)
66                         snd_soc_write(codec, *p, *(p + rt_codec.number / 2));
67                 break;
68
69         case RT_READ_CODEC_INDEX_IOCTL:
70                 if (NULL == rt_codec_ioctl_ops.index_read)
71                         goto err;
72
73                 for (p = buf; p < buf + rt_codec.number / 2; p++)
74                         *(p+rt_codec.number/2) = rt_codec_ioctl_ops.index_read(
75                                                         codec, *p);
76                 if (copy_to_user(rt_codec.buf, buf,
77                         sizeof(*buf) * rt_codec.number))
78                         goto err;
79                 break;
80
81         case RT_WRITE_CODEC_INDEX_IOCTL:
82                 if (NULL == rt_codec_ioctl_ops.index_write)
83                         goto err;
84
85                 for (p = buf; p < buf + rt_codec.number / 2; p++)
86                         rt_codec_ioctl_ops.index_write(codec, *p,
87                                 *(p+rt_codec.number/2));
88                 break;          
89
90         default:
91                 if (NULL == rt_codec_ioctl_ops.ioctl_common)
92                         goto err;
93
94                 rt_codec_ioctl_ops.ioctl_common(hw, file, cmd, arg);
95                 break;
96         }
97
98         kfree(buf);
99         return 0;
100
101 err:
102         kfree(buf);
103         return -EFAULT;
104 }
105
106 static int rt_codec_codec_dump_reg(struct snd_hwdep *hw,
107                 struct file *file, unsigned long arg)
108 {
109         struct snd_soc_codec *codec = hw->private_data;
110         struct rt_codec_cmd __user *_rt_codec =(struct rt_codec_cmd *)arg;
111         struct rt_codec_cmd rt_codec;
112         int i, *buf, number = codec->driver->reg_cache_size;
113
114         dev_dbg(codec->dev, "enter %s, number = %d\n", __func__, number);
115         if (copy_from_user(&rt_codec, _rt_codec, sizeof(rt_codec)))
116                 return -EFAULT;
117         
118         buf = kmalloc(sizeof(*buf) * number, GFP_KERNEL);
119         if (buf == NULL)
120                 return -ENOMEM;
121
122         for (i = 0; i < number/2; i++) {
123                 buf[i] = i << 1;
124                 buf[i + number / 2] = codec->read(codec, buf[i]);
125         }
126         if (copy_to_user(rt_codec.buf, buf, sizeof(*buf) * i))
127                 goto err;
128         rt_codec.number = number;
129         if (copy_to_user(_rt_codec, &rt_codec, sizeof(rt_codec)))
130                 goto err;
131         kfree(buf);
132         return 0;
133
134 err:
135         kfree(buf);
136         return -EFAULT;
137 }
138
139 static int rt_codec_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
140                         unsigned int cmd, unsigned long arg)
141 {
142         switch (cmd) {
143         case RT_READ_ALL_CODEC_REG_IOCTL:
144                 return rt_codec_codec_dump_reg(hw, file, arg);
145
146         default:
147                 return rt_codec_hwdep_ioctl_common(hw, file, cmd, arg);
148         }
149
150         return 0;
151 }
152
153 int realtek_ce_init_hwdep(struct snd_soc_codec *codec)
154 {
155         struct snd_hwdep *hw;
156         struct snd_card *card = codec->card->snd_card;
157         int err;
158
159         dev_dbg(codec->dev, "enter %s\n", __func__);
160
161         if ((err = snd_hwdep_new(card, RT_CE_CODEC_HWDEP_NAME, 0, &hw)) < 0)
162                 return err;
163         
164         strcpy(hw->name, RT_CE_CODEC_HWDEP_NAME);
165         hw->private_data = codec;
166         hw->ops.open = rt_codec_hwdep_open;
167         hw->ops.release = rt_codec_hwdep_release;
168         hw->ops.ioctl = rt_codec_hwdep_ioctl;
169
170         return 0;
171 }
172 EXPORT_SYMBOL_GPL(realtek_ce_init_hwdep);
173 #endif
174
175 struct rt_codec_ops *rt_codec_get_ioctl_ops(void)
176 {
177         return &rt_codec_ioctl_ops;
178 }
179 EXPORT_SYMBOL_GPL(rt_codec_get_ioctl_ops);