bd6910af286c9672adebd33fbcbac5130918c682
[platform/kernel/linux-starfive.git] / sound / oss / dmasound / tas_common.c
1 #include <linux/module.h>
2 #include <linux/slab.h>
3 #include <linux/proc_fs.h>
4 #include <linux/ioport.h>
5 #include <linux/sysctl.h>
6 #include <linux/types.h>
7 #include <linux/i2c.h>
8 #include <linux/init.h>
9 #include <linux/soundcard.h>
10 #include <asm/uaccess.h>
11 #include <asm/errno.h>
12 #include <asm/io.h>
13 #include <asm/prom.h>
14
15 #include "tas_common.h"
16
17 #define CALL0(proc)                                                             \
18         do {                                                                    \
19                 struct tas_data_t *self;                                        \
20                 if (!tas_client || driver_hooks == NULL)                        \
21                         return -1;                                              \
22                 self = dev_get_drvdata(&tas_client->dev);                       \
23                 if (driver_hooks->proc)                                         \
24                         return driver_hooks->proc(self);                        \
25                 else                                                            \
26                         return -EINVAL;                                         \
27         } while (0)
28
29 #define CALL(proc,arg...)                                                       \
30         do {                                                                    \
31                 struct tas_data_t *self;                                        \
32                 if (!tas_client || driver_hooks == NULL)                        \
33                         return -1;                                              \
34                 self = dev_get_drvdata(&tas_client->dev);                       \
35                 if (driver_hooks->proc)                                         \
36                         return driver_hooks->proc(self, ## arg);                \
37                 else                                                            \
38                         return -EINVAL;                                         \
39         } while (0)
40
41
42 static u8 tas_i2c_address = 0x34;
43 static struct i2c_client *tas_client;
44 static struct device_node* tas_node;
45
46 static int tas_attach_adapter(struct i2c_adapter *);
47 static int tas_detach_client(struct i2c_client *);
48
49 struct i2c_driver tas_driver = {
50         .driver = {
51                 .owner  = THIS_MODULE,
52                 .name   = "tas",
53         },
54         .attach_adapter = tas_attach_adapter,
55         .detach_client  = tas_detach_client,
56 };
57
58 struct tas_driver_hooks_t *driver_hooks;
59
60 int
61 tas_register_driver(struct tas_driver_hooks_t *hooks)
62 {
63         driver_hooks = hooks;
64         return 0;
65 }
66
67 int
68 tas_get_mixer_level(int mixer, uint *level)
69 {
70         CALL(get_mixer_level,mixer,level);
71 }
72
73 int
74 tas_set_mixer_level(int mixer,uint level)
75 {
76         CALL(set_mixer_level,mixer,level);
77 }
78
79 int
80 tas_enter_sleep(void)
81 {
82         CALL0(enter_sleep);
83 }
84
85 int
86 tas_leave_sleep(void)
87 {
88         CALL0(leave_sleep);
89 }
90
91 int
92 tas_supported_mixers(void)
93 {
94         CALL0(supported_mixers);
95 }
96
97 int
98 tas_mixer_is_stereo(int mixer)
99 {
100         CALL(mixer_is_stereo,mixer);
101 }
102
103 int
104 tas_stereo_mixers(void)
105 {
106         CALL0(stereo_mixers);
107 }
108
109 int
110 tas_output_device_change(int device_id,int layout_id,int speaker_id)
111 {
112         CALL(output_device_change,device_id,layout_id,speaker_id);
113 }
114
115 int
116 tas_device_ioctl(u_int cmd, u_long arg)
117 {
118         CALL(device_ioctl,cmd,arg);
119 }
120
121 int
122 tas_post_init(void)
123 {
124         CALL0(post_init);
125 }
126
127 static int
128 tas_detect_client(struct i2c_adapter *adapter, int address)
129 {
130         static const char *client_name = "tas Digital Equalizer";
131         struct i2c_client *new_client;
132         int rc = -ENODEV;
133
134         if (!driver_hooks) {
135                 printk(KERN_ERR "tas_detect_client called with no hooks !\n");
136                 return -ENODEV;
137         }
138         
139         new_client = kmalloc(sizeof(*new_client), GFP_KERNEL);
140         if (!new_client)
141                 return -ENOMEM;
142         memset(new_client, 0, sizeof(*new_client));
143
144         new_client->addr = address;
145         new_client->adapter = adapter;
146         new_client->driver = &tas_driver;
147         strlcpy(new_client->name, client_name, DEVICE_NAME_SIZE);
148
149         if (driver_hooks->init(new_client))
150                 goto bail;
151
152         /* Tell the i2c layer a new client has arrived */
153         if (i2c_attach_client(new_client)) {
154                 driver_hooks->uninit(dev_get_drvdata(&new_client->dev));
155                 goto bail;
156         }
157
158         tas_client = new_client;
159         return 0;
160  bail:
161         tas_client = NULL;
162         kfree(new_client);
163         return rc;
164 }
165
166 static int
167 tas_attach_adapter(struct i2c_adapter *adapter)
168 {
169         if (!strncmp(adapter->name, "mac-io", 6))
170                 return tas_detect_client(adapter, tas_i2c_address);
171         return 0;
172 }
173
174 static int
175 tas_detach_client(struct i2c_client *client)
176 {
177         if (client == tas_client) {
178                 driver_hooks->uninit(dev_get_drvdata(&client->dev));
179
180                 i2c_detach_client(client);
181                 kfree(client);
182         }
183         return 0;
184 }
185
186 void
187 tas_cleanup(void)
188 {
189         i2c_del_driver(&tas_driver);
190 }
191
192 int __init
193 tas_init(int driver_id, const char *driver_name)
194 {
195         u32* paddr;
196
197         printk(KERN_INFO "tas driver [%s])\n", driver_name);
198
199 #ifndef CONFIG_I2C_KEYWEST
200         request_module("i2c-keywest");
201 #endif
202         tas_node = find_devices("deq");
203         if (tas_node == NULL)
204                 return -ENODEV;
205         paddr = (u32 *)get_property(tas_node, "i2c-address", NULL);
206         if (paddr) {
207                 tas_i2c_address = (*paddr) >> 1;
208                 printk(KERN_INFO "using i2c address: 0x%x from device-tree\n",
209                                 tas_i2c_address);
210         } else    
211                 printk(KERN_INFO "using i2c address: 0x%x (default)\n",
212                                 tas_i2c_address);
213
214         return i2c_add_driver(&tas_driver);
215 }