diff options
Diffstat (limited to 'sound/soc/codecs/aic326x_tiload.c')
-rw-r--r-- | sound/soc/codecs/aic326x_tiload.c | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/sound/soc/codecs/aic326x_tiload.c b/sound/soc/codecs/aic326x_tiload.c new file mode 100644 index 000000000000..00aa4d4ce7d7 --- /dev/null +++ b/sound/soc/codecs/aic326x_tiload.c @@ -0,0 +1,312 @@ +/* + * linux/sound/soc/codecs/AIC3262_tiload.c + * + * + * Copyright (C) 2010 Texas Instruments, Inc. + * + * + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * History: + * + * Rev 0.1 Tiload support 16-09-2010 + * + * The Tiload programming support is added to AIC3262. + * + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/types.h> +#include <linux/kdev_t.h> +#include <linux/cdev.h> +#include <linux/device.h> +#include <asm/io.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <sound/soc.h> +#include <sound/control.h> + +#include "tlv320aic326x.h" +#include "aic326x_tiload.h" + +/* enable debug prints in the driver */ +#define DEBUG +//#undef DEBUG + +#ifdef DEBUG +#define dprintk(x...) printk(x) +#else +#define dprintk(x...) +#endif + +#ifdef AIC3262_TiLoad + +/* Function prototypes */ +#ifdef REG_DUMP_aic3262 +static void aic3262_dump_page(struct i2c_client *i2c, u8 page); +#endif + +/* externs */ +extern int aic3262_change_page(struct snd_soc_codec *codec, u8 new_page); +extern int aic3262_change_book(struct snd_soc_codec *codec, u8 new_book); +extern int aic3262_write(struct snd_soc_codec *codec, u16 reg, u8 value); +int aic3262_driver_init(struct snd_soc_codec *codec); +/************** Dynamic aic3262 driver, TI LOAD support ***************/ + +static struct cdev *aic3262_cdev; +static int aic3262_major = 0; /* Dynamic allocation of Mjr No. */ +static int aic3262_opened = 0; /* Dynamic allocation of Mjr No. */ +static struct snd_soc_codec *aic3262_codec; +struct class *tiload_class; +static unsigned int magic_num = 0xE0; + +/******************************** Debug section *****************************/ + +#ifdef REG_DUMP_aic3262 +/* + *---------------------------------------------------------------------------- + * Function : aic3262_dump_page + * Purpose : Read and display one codec register page, for debugging purpose + *---------------------------------------------------------------------------- + */ +static void aic3262_dump_page(struct i2c_client *i2c, u8 page) +{ + int i; + u8 data; + u8 test_page_array[8]; + + dprintk("TiLoad DRIVER : %s\n", __FUNCTION__); + aic3262_change_page(codec, page); + + data = 0x0; + + i2c_master_send(i2c, data, 1); + i2c_master_recv(i2c, test_page_array, 8); + + printk("\n------- aic3262 PAGE %d DUMP --------\n", page); + for (i = 0; i < 8; i++) { + printk(" [ %d ] = 0x%x\n", i, test_page_array[i]); + } +} +#endif + +/* + *---------------------------------------------------------------------------- + * Function : tiload_open + * + * Purpose : open method for aic3262-tiload programming interface + *---------------------------------------------------------------------------- + */ +static int tiload_open(struct inode *in, struct file *filp) +{ + dprintk("TiLoad DRIVER : %s\n", __FUNCTION__); + if (aic3262_opened) { + printk("%s device is already opened\n", "aic3262"); + printk("%s: only one instance of driver is allowed\n", + "aic3262"); + return -1; + } + aic3262_opened++; + return 0; +} + +/* + *---------------------------------------------------------------------------- + * Function : tiload_release + * + * Purpose : close method for aic3262_tilaod programming interface + *---------------------------------------------------------------------------- + */ +static int tiload_release(struct inode *in, struct file *filp) +{ + dprintk("TiLoad DRIVER : %s\n", __FUNCTION__); + aic3262_opened--; + return 0; +} + +/* + *---------------------------------------------------------------------------- + * Function : tiload_read + * + * Purpose : read method for mini dsp programming interface + *---------------------------------------------------------------------------- + */ +static ssize_t tiload_read(struct file *file, char __user * buf, + size_t count, loff_t * offset) +{ + static char rd_data[8]; + char reg_addr; + size_t size; + #ifdef DEBUG + int i; + #endif + struct i2c_client *i2c = aic3262_codec->control_data; + + dprintk("TiLoad DRIVER : %s\n", __FUNCTION__); + if (count > 128) { + printk("Max 128 bytes can be read\n"); + count = 128; + } + + /* copy register address from user space */ + size = copy_from_user(®_addr, buf, 1); + if (size != 0) { + printk("read: copy_from_user failure\n"); + return -1; + } + /* Send the address to device thats is to be read */ + + if (i2c_master_send(i2c, ®_addr, 1) != 1) { + dprintk("Can not write register address\n"); + return -1; + } + /* read the codec device registers */ + size = i2c_master_recv(i2c, rd_data, count); +#ifdef DEBUG + printk(KERN_ERR "read size = %d, reg_addr= %x , count = %d\n", + (int)size, reg_addr, (int)count); + for (i = 0; i < (int)size; i++) { + printk(KERN_ERR "rd_data[%d]=%x\n", i, rd_data[i]); + } +#endif + if (size != count) { + printk("read %d registers from the codec\n", size); + } + + if (copy_to_user(buf, rd_data, size) != 0) { + dprintk("copy_to_user failed\n"); + return -1; + } + + return size; +} + +/* + *---------------------------------------------------------------------------- + * Function : tiload_write + * + * Purpose : write method for aic3262_tiload programming interface + *---------------------------------------------------------------------------- + */ +static ssize_t tiload_write(struct file *file, const char __user * buf, + size_t count, loff_t * offset) +{ + static char wr_data[8]; + u8 pg_no; + #ifdef DEBUG + int i; + #endif + struct i2c_client *i2c = aic3262_codec->control_data; + struct aic3262_priv *aic3262_private = snd_soc_codec_get_drvdata(aic3262_codec); + + dprintk("TiLoad DRIVER : %s\n", __FUNCTION__); + /* copy buffer from user space */ + if (copy_from_user(wr_data, buf, count)) { + printk("copy_from_user failure\n"); + return -1; + } +#ifdef DEBUG + printk(KERN_ERR "write size = %d\n", (int)count); + for (i = 0; i < (int)count; i++) { + printk(KERN_INFO "\nwr_data[%d]=%x\n", i, wr_data[i]); + } +#endif + if (wr_data[0] == 0) { + aic3262_change_page(aic3262_codec, wr_data[1]); + return count; + } + pg_no = aic3262_private->page_no; + + if ((wr_data[0] == 127) && (pg_no == 0)) { + aic3262_change_book(aic3262_codec, wr_data[1]); + return count; + } + return i2c_master_send(i2c, wr_data, count); +} + +static int tiload_ioctl( struct file *filp, + unsigned int cmd, unsigned long arg) +{ + int num = 0; + void __user *argp = (void __user *)arg; + if (_IOC_TYPE(cmd) != aic3262_IOC_MAGIC) + return -ENOTTY; + + dprintk("TiLoad DRIVER : %s\n", __FUNCTION__); + switch (cmd) { + case aic3262_IOMAGICNUM_GET: + num = copy_to_user(argp, &magic_num, sizeof(int)); + break; + case aic3262_IOMAGICNUM_SET: + num = copy_from_user(&magic_num, argp, sizeof(int)); + break; + } + return num; +} + +/*********** File operations structure for aic3262-tiload programming *************/ +static struct file_operations aic3262_fops = { + .owner = THIS_MODULE, + .open = tiload_open, + .release = tiload_release, + .read = tiload_read, + .write = tiload_write, + .unlocked_ioctl = tiload_ioctl, +}; + +/* + *---------------------------------------------------------------------------- + * Function : aic3262_driver_init + * + * Purpose : Register a char driver for dynamic aic3262-tiload programming + *---------------------------------------------------------------------------- + */ +int aic3262_driver_init(struct snd_soc_codec *codec) +{ + int result; + + dev_t dev = MKDEV(aic3262_major, 0); + printk("TiLoad DRIVER : %s\n", __FUNCTION__); + aic3262_codec = codec; + + printk("allocating dynamic major number\n"); + + result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME); + if (result < 0) { + printk("cannot allocate major number %d\n", aic3262_major); + return result; + } + tiload_class = class_create(THIS_MODULE, DEVICE_NAME); + aic3262_major = MAJOR(dev); + printk("allocated Major Number: %d\n", aic3262_major); + + aic3262_cdev = cdev_alloc(); + cdev_init(aic3262_cdev, &aic3262_fops); + aic3262_cdev->owner = THIS_MODULE; + aic3262_cdev->ops = &aic3262_fops; + + if (cdev_add(aic3262_cdev, dev, 1) < 0) { + dprintk("aic3262_driver: cdev_add failed \n"); + unregister_chrdev_region(dev, 1); + aic3262_cdev = NULL; + return 1; + } + printk("Registered aic3262 TiLoad driver, Major number: %d \n", + aic3262_major); + //class_device_create(tiload_class, NULL, dev, NULL, DEVICE_NAME, 0); + return 0; +} + +#endif |