blob: bd6910af286c9672adebd33fbcbac5130918c682 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#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
42static u8 tas_i2c_address = 0x34;
43static struct i2c_client *tas_client;
44static struct device_node* tas_node;
45
46static int tas_attach_adapter(struct i2c_adapter *);
47static int tas_detach_client(struct i2c_client *);
48
49struct i2c_driver tas_driver = {
Laurent Riffardd74cdab2005-11-26 20:46:32 +010050 .driver = {
51 .owner = THIS_MODULE,
52 .name = "tas",
53 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 .attach_adapter = tas_attach_adapter,
55 .detach_client = tas_detach_client,
56};
57
58struct tas_driver_hooks_t *driver_hooks;
59
60int
61tas_register_driver(struct tas_driver_hooks_t *hooks)
62{
63 driver_hooks = hooks;
64 return 0;
65}
66
67int
68tas_get_mixer_level(int mixer, uint *level)
69{
70 CALL(get_mixer_level,mixer,level);
71}
72
73int
74tas_set_mixer_level(int mixer,uint level)
75{
76 CALL(set_mixer_level,mixer,level);
77}
78
79int
80tas_enter_sleep(void)
81{
82 CALL0(enter_sleep);
83}
84
85int
86tas_leave_sleep(void)
87{
88 CALL0(leave_sleep);
89}
90
91int
92tas_supported_mixers(void)
93{
94 CALL0(supported_mixers);
95}
96
97int
98tas_mixer_is_stereo(int mixer)
99{
100 CALL(mixer_is_stereo,mixer);
101}
102
103int
104tas_stereo_mixers(void)
105{
106 CALL0(stereo_mixers);
107}
108
109int
110tas_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
115int
116tas_device_ioctl(u_int cmd, u_long arg)
117{
118 CALL(device_ioctl,cmd,arg);
119}
120
121int
122tas_post_init(void)
123{
124 CALL0(post_init);
125}
126
127static int
128tas_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
166static int
167tas_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
174static int
175tas_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
186void
187tas_cleanup(void)
188{
189 i2c_del_driver(&tas_driver);
190}
191
192int __init
193tas_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}