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 42static u8 tas_i2c_address = 0x34; 43static struct i2c_client *tas_client; 44 45static int tas_attach_adapter(struct i2c_adapter *); 46static int tas_detach_client(struct i2c_client *); 47 48struct i2c_driver tas_driver = { 49 .driver = { 50 .name = "tas", 51 }, 52 .attach_adapter = tas_attach_adapter, 53 .detach_client = tas_detach_client, 54}; 55 56struct tas_driver_hooks_t *driver_hooks; 57 58int 59tas_register_driver(struct tas_driver_hooks_t *hooks) 60{ 61 driver_hooks = hooks; 62 return 0; 63} 64 65int 66tas_get_mixer_level(int mixer, uint *level) 67{ 68 CALL(get_mixer_level,mixer,level); 69} 70 71int 72tas_set_mixer_level(int mixer,uint level) 73{ 74 CALL(set_mixer_level,mixer,level); 75} 76 77int 78tas_enter_sleep(void) 79{ 80 CALL0(enter_sleep); 81} 82 83int 84tas_leave_sleep(void) 85{ 86 CALL0(leave_sleep); 87} 88 89int 90tas_supported_mixers(void) 91{ 92 CALL0(supported_mixers); 93} 94 95int 96tas_mixer_is_stereo(int mixer) 97{ 98 CALL(mixer_is_stereo,mixer); 99} 100 101int 102tas_stereo_mixers(void) 103{ 104 CALL0(stereo_mixers); 105} 106 107int 108tas_output_device_change(int device_id,int layout_id,int speaker_id) 109{ 110 CALL(output_device_change,device_id,layout_id,speaker_id); 111} 112 113int 114tas_device_ioctl(u_int cmd, u_long arg) 115{ 116 CALL(device_ioctl,cmd,arg); 117} 118 119int 120tas_post_init(void) 121{ 122 CALL0(post_init); 123} 124 125static int 126tas_detect_client(struct i2c_adapter *adapter, int address) 127{ 128 static const char *client_name = "tas Digital Equalizer"; 129 struct i2c_client *new_client; 130 int rc = -ENODEV; 131 132 if (!driver_hooks) { 133 printk(KERN_ERR "tas_detect_client called with no hooks !\n"); 134 return -ENODEV; 135 } 136 137 new_client = kzalloc(sizeof(*new_client), GFP_KERNEL); 138 if (!new_client) 139 return -ENOMEM; 140 141 new_client->addr = address; 142 new_client->adapter = adapter; 143 new_client->driver = &tas_driver; 144 strlcpy(new_client->name, client_name, DEVICE_NAME_SIZE); 145 146 if (driver_hooks->init(new_client)) 147 goto bail; 148 149 /* Tell the i2c layer a new client has arrived */ 150 if (i2c_attach_client(new_client)) { 151 driver_hooks->uninit(dev_get_drvdata(&new_client->dev)); 152 goto bail; 153 } 154 155 tas_client = new_client; 156 return 0; 157 bail: 158 tas_client = NULL; 159 kfree(new_client); 160 return rc; 161} 162 163static int 164tas_attach_adapter(struct i2c_adapter *adapter) 165{ 166 if (!strncmp(adapter->name, "mac-io", 6)) 167 return tas_detect_client(adapter, tas_i2c_address); 168 return 0; 169} 170 171static int 172tas_detach_client(struct i2c_client *client) 173{ 174 if (client == tas_client) { 175 driver_hooks->uninit(dev_get_drvdata(&client->dev)); 176 177 i2c_detach_client(client); 178 kfree(client); 179 } 180 return 0; 181} 182 183void 184tas_cleanup(void) 185{ 186 i2c_del_driver(&tas_driver); 187} 188 189int __init 190tas_init(int driver_id, const char *driver_name) 191{ 192 const u32* paddr; 193 struct device_node *tas_node; 194 195 printk(KERN_INFO "tas driver [%s])\n", driver_name); 196 197#ifndef CONFIG_I2C_POWERMAC 198 request_module("i2c-powermac"); 199#endif 200 tas_node = of_find_node_by_name("deq"); 201 if (tas_node == NULL) 202 return -ENODEV; 203 paddr = of_get_property(tas_node, "i2c-address", NULL); 204 if (paddr) { 205 tas_i2c_address = (*paddr) >> 1; 206 printk(KERN_INFO "using i2c address: 0x%x from device-tree\n", 207 tas_i2c_address); 208 } else 209 printk(KERN_INFO "using i2c address: 0x%x (default)\n", 210 tas_i2c_address); 211 of_node_put(tas_node); 212 213 return i2c_add_driver(&tas_driver); 214} 215