#include #include #include #include #include #include #include #include #include #include #include #include #include #include "tas_common.h" #define CALL0(proc) \ do { \ struct tas_data_t *self; \ if (!tas_client || driver_hooks == NULL) \ return -1; \ self = dev_get_drvdata(&tas_client->dev); \ if (driver_hooks->proc) \ return driver_hooks->proc(self); \ else \ return -EINVAL; \ } while (0) #define CALL(proc,arg...) \ do { \ struct tas_data_t *self; \ if (!tas_client || driver_hooks == NULL) \ return -1; \ self = dev_get_drvdata(&tas_client->dev); \ if (driver_hooks->proc) \ return driver_hooks->proc(self, ## arg); \ else \ return -EINVAL; \ } while (0) static u8 tas_i2c_address = 0x34; static struct i2c_client *tas_client; static int tas_attach_adapter(struct i2c_adapter *); static int tas_detach_client(struct i2c_client *); struct i2c_driver tas_driver = { .driver = { .name = "tas", }, .attach_adapter = tas_attach_adapter, .detach_client = tas_detach_client, }; struct tas_driver_hooks_t *driver_hooks; int tas_register_driver(struct tas_driver_hooks_t *hooks) { driver_hooks = hooks; return 0; } int tas_get_mixer_level(int mixer, uint *level) { CALL(get_mixer_level,mixer,level); } int tas_set_mixer_level(int mixer,uint level) { CALL(set_mixer_level,mixer,level); } int tas_enter_sleep(void) { CALL0(enter_sleep); } int tas_leave_sleep(void) { CALL0(leave_sleep); } int tas_supported_mixers(void) { CALL0(supported_mixers); } int tas_mixer_is_stereo(int mixer) { CALL(mixer_is_stereo,mixer); } int tas_stereo_mixers(void) { CALL0(stereo_mixers); } int tas_output_device_change(int device_id,int layout_id,int speaker_id) { CALL(output_device_change,device_id,layout_id,speaker_id); } int tas_device_ioctl(u_int cmd, u_long arg) { CALL(device_ioctl,cmd,arg); } int tas_post_init(void) { CALL0(post_init); } static int tas_detect_client(struct i2c_adapter *adapter, int address) { static const char *client_name = "tas Digital Equalizer"; struct i2c_client *new_client; int rc = -ENODEV; if (!driver_hooks) { printk(KERN_ERR "tas_detect_client called with no hooks !\n"); return -ENODEV; } new_client = kzalloc(sizeof(*new_client), GFP_KERNEL); if (!new_client) return -ENOMEM; new_client->addr = address; new_client->adapter = adapter; new_client->driver = &tas_driver; strlcpy(new_client->name, client_name, DEVICE_NAME_SIZE); if (driver_hooks->init(new_client)) goto bail; /* Tell the i2c layer a new client has arrived */ if (i2c_attach_client(new_client)) { driver_hooks->uninit(dev_get_drvdata(&new_client->dev)); goto bail; } tas_client = new_client; return 0; bail: tas_client = NULL; kfree(new_client); return rc; } static int tas_attach_adapter(struct i2c_adapter *adapter) { if (!strncmp(adapter->name, "mac-io", 6)) return tas_detect_client(adapter, tas_i2c_address); return 0; } static int tas_detach_client(struct i2c_client *client) { if (client == tas_client) { driver_hooks->uninit(dev_get_drvdata(&client->dev)); i2c_detach_client(client); kfree(client); } return 0; } void tas_cleanup(void) { i2c_del_driver(&tas_driver); } int __init tas_init(int driver_id, const char *driver_name) { const u32* paddr; struct device_node *tas_node; printk(KERN_INFO "tas driver [%s])\n", driver_name); #ifndef CONFIG_I2C_POWERMAC request_module("i2c-powermac"); #endif tas_node = of_find_node_by_name("deq"); if (tas_node == NULL) return -ENODEV; paddr = of_get_property(tas_node, "i2c-address", NULL); if (paddr) { tas_i2c_address = (*paddr) >> 1; printk(KERN_INFO "using i2c address: 0x%x from device-tree\n", tas_i2c_address); } else printk(KERN_INFO "using i2c address: 0x%x (default)\n", tas_i2c_address); of_node_put(tas_node); return i2c_add_driver(&tas_driver); }