From: Cyril Germond Date: Tue, 15 Nov 2011 07:11:35 +0000 (+0100) Subject: Audio: Audience kernel driver migration to k308 X-Git-Tag: 2.1b_release~1885 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=267cd9b6b8d623e9cbab3f4e0c9e7ccbd22582ac;p=kernel%2Fkernel-mfld-blackbay.git Audio: Audience kernel driver migration to k308 BZ: 14425 Integration of Audience driver in k3.08 kernel. Rebase of latest Audeince driver on initial import. Change-Id: Iaead5b2e15ddfbe42c5f32a32103311d8536bd9a Signed-off-by: Cyril Germond Reviewed-on: http://android.intel.com:8080/24609 Reviewed-by: Gross, Mark Tested-by: Gross, Mark --- diff --git a/arch/x86/configs/i386_mfld_defconfig b/arch/x86/configs/i386_mfld_defconfig index b171497..53bed50 100644 --- a/arch/x86/configs/i386_mfld_defconfig +++ b/arch/x86/configs/i386_mfld_defconfig @@ -691,7 +691,54 @@ CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_HD is not set # CONFIG_BLK_DEV_RBD is not set # CONFIG_SENSORS_LIS3LV02D is not set -# CONFIG_MISC_DEVICES is not set +CONFIG_MISC_DEVICES=y +# CONFIG_AD525X_DPOT is not set +# CONFIG_ANDROID_PMEM is not set +# CONFIG_IBM_ASM is not set +# CONFIG_PHANTOM is not set +# CONFIG_INTEL_MID_PTI is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_KERNEL_DEBUGGER_CORE is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_SENSORS_AK8975 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_UID_STAT is not set +# CONFIG_VMWARE_BALLOON is not set +# CONFIG_BMP085 is not set +# CONFIG_PCH_PHUB is not set +# CONFIG_APANIC is not set +CONFIG_A1026=y +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_CB710_CORE is not set +# CONFIG_IWMC3200TOP is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set CONFIG_HAVE_IDE=y # CONFIG_IDE is not set diff --git a/arch/x86/platform/mfld/blackbay_pr2.c b/arch/x86/platform/mfld/blackbay_pr2.c index 5bad9bd..5e1fbb4 100644 --- a/arch/x86/platform/mfld/blackbay_pr2.c +++ b/arch/x86/platform/mfld/blackbay_pr2.c @@ -21,6 +21,7 @@ #include #include #include +#include static u8 mxt_valid_interrupt(void) { @@ -77,6 +78,92 @@ static struct lis3dh_acc_platform_data lis3dh_pdata = { .gpio_int2 = 61, }; +/* AUDIENCE es305 PLATFORM DATA */ +#define AUDIENCE_WAKEUP_GPIO "audience-wakeup" +#define AUDIENCE_RESET_GPIO "audience-reset" +/* FIXME: Although a1026_platform_data has defined gpio number, but don't know + * why add reset/wakeup function in the platform_data structure. + * Currently set the gpio a fixed number, after changed driver code, + * will remove below global define */ +#define A1026_WAKEUP_GPIO 159 +#define A1026_RESET_GPIO 111 + +static int audience_request_resources(struct i2c_client *client) +{ + struct a1026_platform_data *pdata = (struct a1026_platform_data *) + client->dev.platform_data; + int ret; + + pr_debug("Audience: request ressource audience\n"); + if (!pdata) + return -1; + ret = gpio_request(pdata->gpio_a1026_wakeup, AUDIENCE_WAKEUP_GPIO); + if (ret) { + dev_err(&client->dev, "Request AUDIENCE WAKEUP GPIO %d fails %d\n", + pdata->gpio_a1026_wakeup, ret); + return -1; + } + ret = gpio_direction_output(pdata->gpio_a1026_wakeup, 0); + if (ret) { + dev_err(&client->dev, "Set GPIO Direction fails %d\n", ret); + goto err_wake; + } + + ret = gpio_request(pdata->gpio_a1026_reset, AUDIENCE_RESET_GPIO); + if (ret) { + dev_err(&client->dev, + "Request for Audience reset GPIO %d fails %d\n", + pdata->gpio_a1026_reset, ret); + goto err_wake; + } + ret = gpio_direction_output(pdata->gpio_a1026_reset, 0); + if (ret) { + dev_err(&client->dev, "Set GPIO Direction fails %d\n", ret); + goto err_reset; + } + if (mfld_board_id() == MFLD_BID_PR3 || + mfld_board_id() == MFLD_BID_PR3_PNP) + sprintf(pdata->firmware_name, "%s", "vpimg_es305b.bin"); + else + sprintf(pdata->firmware_name, "%s", "vpimg.bin"); + + return 0; +err_reset: + gpio_free(pdata->gpio_a1026_reset); +err_wake: + gpio_free(pdata->gpio_a1026_wakeup); + return -1; +} + +static void audience_free_resources(struct i2c_client *client) +{ + struct a1026_platform_data *pdata = (struct a1026_platform_data *) + &client->dev.platform_data; + + gpio_free(pdata->gpio_a1026_wakeup); + gpio_free(pdata->gpio_a1026_reset); +} + +static void audience_wake_up(bool state) +{ + gpio_set_value(A1026_WAKEUP_GPIO, state); + pr_debug("Audience: WAKE UP %d\n", state); +} + +static void audience_reset(bool state) +{ + gpio_set_value(A1026_RESET_GPIO, state); + pr_debug("Audience: RESET %d\n", state); +} + +static struct a1026_platform_data mfld_audience_platform_data = { + .gpio_a1026_wakeup = A1026_WAKEUP_GPIO, + .gpio_a1026_reset = A1026_RESET_GPIO, + .request_resources = audience_request_resources, + .wakeup = audience_wake_up, + .reset = audience_reset, +}; + static struct ms5607_platform_data baro_pdata = { .poll_interval = 100, .min_interval = 0, @@ -113,6 +200,12 @@ static struct i2c_board_info pr2_i2c_bus5_devs[] = { .irq = LTR502_GPIO, .addr = 0x1d, }, + { + .type = "audience_es305", + .irq = 0xff, + .addr = 0x3e, + .platform_data = &mfld_audience_platform_data, + }, }; static struct gpio_keys_button gpio_button[] = { diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index e178d73..b918309 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -538,6 +538,7 @@ config APANIC_PLABEL config A1026 tristate "Audience a1026/eS305 Voice Processor" depends on I2C + depends on SND_INTEL_SST help Provides an interface to the Audience voice processing unit via an I2C bus interface. diff --git a/drivers/misc/a1026.c b/drivers/misc/a1026.c index 2eb7f94..398f352 100644 --- a/drivers/misc/a1026.c +++ b/drivers/misc/a1026.c @@ -13,46 +13,42 @@ * */ -#include +#include +#include #include #include -#include #include -#include #include #include -#include -#include -#include -#include #include /* FIXME: once sound moves we can fix this */ +/* #include */ #include "../staging/intel_sst/intel_sst.h" +#include +#include #define DEBUG (0) #define ENABLE_DIAG_IOCTLS (0) - +#define ES305_I2C_CMD_FIFO_SIZE (128) /* Max cmd length on es305 side is 252 */ /* * This driver is based on the eS305-UG-APIGINTEL-V0 2.pdf spec * for the eS305 Voice Processor */ struct vp_ctxt { - unsigned char *data; - unsigned int img_size; struct i2c_client *i2c_dev; struct a1026_platform_data *pdata; + unsigned long open; + int suspended; + struct mutex mutex; } *es305; static int execute_cmdmsg(unsigned int msg, struct vp_ctxt *vp); static int suspend(struct vp_ctxt *vp); -static struct mutex a1026_lock; -static int es305_opened; -static int es305_suspended; enum bool {gpio_l, gpio_h}; -static int es305_i2c_read(char *rxData, int length, struct vp_ctxt *the_vp) +static int es305_i2c_read(u8 *rxData, int length, struct vp_ctxt *the_vp) { int rc; struct i2c_client *client = the_vp->i2c_dev; @@ -82,7 +78,7 @@ static int es305_i2c_read(char *rxData, int length, struct vp_ctxt *the_vp) return 0; } -static int es305_i2c_write(char *txData, int length, struct vp_ctxt *the_vp) +static int es305_i2c_write(const u8 *txData, int length, struct vp_ctxt *the_vp) { int rc; struct i2c_client *client = the_vp->i2c_dev; @@ -103,7 +99,7 @@ static int es305_i2c_write(char *txData, int length, struct vp_ctxt *the_vp) #if DEBUG { - int; + int i; for (i = 0; i < length; i++) pr_debug("%s: tx[%d] = %2x\n", __func__, i, txData[i]); } @@ -115,7 +111,7 @@ static int es305_i2c_write(char *txData, int length, struct vp_ctxt *the_vp) static void es305_i2c_sw_reset(unsigned int reset_cmd, struct vp_ctxt *vp) { int rc; - unsigned char msgbuf[4]; + u8 msgbuf[4]; msgbuf[0] = (reset_cmd >> 24) & 0xFF; msgbuf[1] = (reset_cmd >> 16) & 0xFF; @@ -132,28 +128,17 @@ static void es305_i2c_sw_reset(unsigned int reset_cmd, struct vp_ctxt *vp) static int es305_open(struct inode *inode, struct file *file) { - int rc = 0; - mutex_lock(&a1026_lock); - if (es305_opened) { - pr_debug("%s: busy\n", __func__); - rc = -EBUSY; - goto done; - } + /* Check if device is already open */ + if (test_and_set_bit(0, &es305->open)) + return -EBUSY; + file->private_data = es305; - es305->img_size = 0; - es305_opened = 1; -done: - mutex_unlock(&a1026_lock); - return rc; + return 0; } - static int es305_release(struct inode *inode, struct file *file) { - mutex_lock(&a1026_lock); - es305_opened = 0; - mutex_unlock(&a1026_lock); - + clear_bit(0, &es305->open); return 0; } @@ -168,14 +153,14 @@ static int suspend(struct vp_ctxt *vp) goto set_suspend_err; } - es305_suspended = 1; + vp->suspended = 1; msleep(120); /* 120 defined by fig 2 of eS305 as the time to wait before clock gating */ rc = intel_sst_set_pll(false, SST_PLL_AUDIENCE); if (rc) pr_err("ipc clk disable command failed: %d\n", rc); -set_suspend_err: +set_suspend_err: return rc; } @@ -185,11 +170,15 @@ static ssize_t es305_bootup_init(struct vp_ctxt *vp) int remaining; int retry = RETRY_CNT; int i; - unsigned char *index; - char buf[2]; + const u8 *index; + u8 buf[2]; const struct firmware *fw_entry; + char *firmware_name = vp->pdata->firmware_name; + + if (firmware_name == NULL || firmware_name[0] == '\0') + firmware_name = "vpimg.bin"; - if (request_firmware(&fw_entry, "vpimg.bin", &vp->i2c_dev->dev)) { + if (request_firmware(&fw_entry, firmware_name, &vp->i2c_dev->dev)) { dev_err(&vp->i2c_dev->dev, "Firmware not available\n"); return -EFAULT; } @@ -234,7 +223,7 @@ static ssize_t es305_bootup_init(struct vp_ctxt *vp) } pr_debug("%s:ACK = %d\n", __func__, buf[0]); - remaining = fw_entry->size; + remaining = fw_entry->size / I2C_SMBUS_BLOCK_MAX; index = fw_entry->data; pr_debug("%s: starting to load image (%d passes)...\n", @@ -242,17 +231,17 @@ static ssize_t es305_bootup_init(struct vp_ctxt *vp) remaining); for (i = 0; i < remaining; i++) { - rc = es305_i2c_write(index, 1, vp); - index++; + rc = es305_i2c_write(index, I2C_SMBUS_BLOCK_MAX, vp); + index += I2C_SMBUS_BLOCK_MAX; if (rc < 0) break; } - pr_debug("%s: starting to load image (%s index)...\n", - __func__, - index); + if (rc >= 0 && fw_entry->size % I2C_SMBUS_BLOCK_MAX) + rc = es305_i2c_write(index, fw_entry->size % + I2C_SMBUS_BLOCK_MAX, vp); if (rc < 0) { - pr_debug("%s: fw load error %d (%d retries left)\n", + pr_err("%s: fw load error %d (%d retries left)\n", __func__, rc, retry); continue; } @@ -272,8 +261,7 @@ static ssize_t es305_bootup_init(struct vp_ctxt *vp) pass = 1; break; } - rc = suspend(vp); - if (pass && !rc) + if (pass) pr_debug("%s: initialized!\n", __func__); else pr_err("%s: initialization failed\n", __func__); @@ -286,7 +274,7 @@ static ssize_t chk_wakeup_es305(struct vp_ctxt *the_vp) { int rc = 0, retry = 3; - if (es305_suspended == 1) { + if (the_vp->suspended == 1) { the_vp->pdata->wakeup(gpio_l); msleep(120); /* fig 3 eS305 spec. BUGBUG should be 30 */ @@ -300,8 +288,9 @@ static ssize_t chk_wakeup_es305(struct vp_ctxt *the_vp) goto wakeup_sync_err; } - es305_suspended = 0; + the_vp->suspended = 0; } + wakeup_sync_err: return rc; } @@ -310,8 +299,8 @@ int execute_cmdmsg(unsigned int msg, struct vp_ctxt *vp) { int rc; int retries, pass = 0; - unsigned char msgbuf[4]; - unsigned char chkbuf[4]; + u8 msgbuf[4]; + u8 chkbuf[4]; unsigned int sw_reset; sw_reset = ((A100_msg_BootloadInitiate << 16) | RESET_IMMEDIATE); @@ -382,91 +371,118 @@ int execute_cmdmsg(unsigned int msg, struct vp_ctxt *vp) return rc; } - -static ssize_t es305_write(struct file *file, char __user *buff, +static ssize_t es305_write(struct file *file, const char __user *buff, size_t count, loff_t *offp) { - int rc, msg_buf_count, i, num_fourbyte; + int rc; + unsigned int i, j, sw_reset; + unsigned int nb_block, nb_sub_block; + unsigned int msg_buf_count, size_cmd_snd, remaining; unsigned char *kbuf; - unsigned int sw_reset; struct vp_ctxt *the_vp; +#if DEBUG unsigned char msgbuf[4]; - int size_cmd_snd = 4; +#endif - the_vp = file->private_data; - if (!the_vp) - return -EINVAL; sw_reset = ((A100_msg_BootloadInitiate << 16) | RESET_IMMEDIATE); + + mutex_lock(&es305->mutex); + + the_vp = file->private_data; + if (!the_vp) { + rc = -EINVAL; + goto out_unlock; + } + rc = chk_wakeup_es305(the_vp); if (rc < 0) - return rc; + goto out_unlock; + kbuf = kmalloc(count, GFP_KERNEL); - if (!kbuf) - return -ENOMEM; + if (!kbuf) { + rc = -ENOMEM; + goto out_unlock; + } if (copy_from_user(kbuf, buff, count)) { - kfree(kbuf); - return -EFAULT; + rc = -EFAULT; + goto out_kfree; } #if DEBUG - { - - size_cmd_snd = count; for (i = 0; i < count; i++) pr_debug("%s: kbuf %x\n", __func__, kbuf[i]); - } #endif + size_cmd_snd = ES305_I2C_CMD_FIFO_SIZE; msg_buf_count = 0; - num_fourbyte = count / size_cmd_snd; - for (i = 0; i < num_fourbyte ; i++) { - rc = es305_i2c_write(&kbuf[msg_buf_count], - size_cmd_snd, the_vp); - if (rc < 0) { - pr_err("ES305 CMD block write error!\n"); - es305_i2c_sw_reset(sw_reset, the_vp); - kfree(kbuf); - return rc; + nb_block = count / size_cmd_snd; + nb_sub_block = size_cmd_snd / I2C_SMBUS_BLOCK_MAX; + for (i = 0; i < nb_block; i++) { + for (j = 0; j < nb_sub_block; j++) { + rc = es305_i2c_write(&kbuf[msg_buf_count], + I2C_SMBUS_BLOCK_MAX, the_vp); + if (rc < 0) { + pr_err("ES305 CMD block write error!\n"); + es305_i2c_sw_reset(sw_reset, the_vp); + goto out_kfree; + } + msg_buf_count += I2C_SMBUS_BLOCK_MAX; + pr_debug("write OK block %d sub-block %d\n", i, j); } - mdelay(1); -#if DEBUG - { - memset(msgbuf, 0, sizeof(msgbuf)); - rc = es305_i2c_read(msgbuf, 4, the_vp); + usleep_range(1*USEC_PER_MSEC, 2*USEC_PER_MSEC); + } + + remaining = count - msg_buf_count; + if (rc >= 0 && remaining) { + nb_sub_block = remaining / I2C_SMBUS_BLOCK_MAX; + for (i = 0; i < nb_sub_block; i++) { + rc = es305_i2c_write(&kbuf[msg_buf_count], + I2C_SMBUS_BLOCK_MAX, the_vp); + if (rc < 0) { + pr_err("ES305 CMD block write error!\n"); + es305_i2c_sw_reset(sw_reset, the_vp); + goto out_kfree; + } + msg_buf_count += I2C_SMBUS_BLOCK_MAX; + remaining -= I2C_SMBUS_BLOCK_MAX; + pr_debug("write OK last block sub-block %d\n", i); + } + } + + if (rc >= 0 && remaining) { + rc = es305_i2c_write(&kbuf[msg_buf_count], remaining, the_vp); if (rc < 0) { - pr_err("ES305 CMD block read error!\n"); + pr_err("ES305 CMD block write error!\n"); es305_i2c_sw_reset(sw_reset, the_vp); - return rc; + goto out_kfree; } - if (!(kbuf[msg_buf_count] == msgbuf[0] && - kbuf[msg_buf_count + 1] == msgbuf[1] && - kbuf[msg_buf_count + 2] == msgbuf[2] && - kbuf[msg_buf_count + 3] == msgbuf[3])) { - pr_err("E305 cmd not ack'ed\n"); - return -ENXIO; - } - pr_debug("ES305 WRITE:(0x%.2x%.2x%.2x%.2x)\n", - kbuf[msg_buf_count], kbuf[msg_buf_count + 1], - kbuf[msg_buf_count + 2], kbuf[msg_buf_count + 3]); - pr_debug("ES305 READ:(0x%.2x%.2x%.2x%.2x)\n", - msgbuf[0], msgbuf[1], msgbuf[2], msgbuf[3]); - } -#endif - msg_buf_count += 4; + pr_debug("write OK remaining %d\n", remaining); } + + rc = count; +out_kfree: kfree(kbuf); - return count; +out_unlock: + mutex_unlock(&es305->mutex); + return rc; } -static ssize_t es305_read(struct file *file, char __user *buff, - size_t count, loff_t *offp) +static ssize_t es305_read(struct file *file, char __user *buff, size_t count, + loff_t *offp) { - unsigned char kbuf[4]; + u8 kbuf[4]; struct vp_ctxt *the_vp; + mutex_lock(&es305->mutex); + the_vp = file->private_data; - if (!the_vp) + if (!the_vp) { + mutex_unlock(&es305->mutex); return -EINVAL; + } + es305_i2c_read(kbuf, 4, the_vp); + + mutex_unlock(&es305->mutex); #if DEBUG { int i; @@ -476,18 +492,18 @@ static ssize_t es305_read(struct file *file, char __user *buff, #endif if (copy_to_user(buff, kbuf, 4)) return -EFAULT; + return 4; } - - -static long a1026_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) +static long es305_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct vp_ctxt *the_vp; - void __user *argp = (void __user *)arg; int rc; - pr_debug("%s: ioctl start\n", __func__); + + pr_debug("-> %s\n", __func__); + + if (file && file->private_data) the_vp = file->private_data; else @@ -496,16 +512,22 @@ static long a1026_ioctl(struct file *file, unsigned int cmd, switch (cmd) { case A1026_BOOTUP_INIT: + mutex_lock(&the_vp->mutex); rc = es305_bootup_init(the_vp); + mutex_unlock(&the_vp->mutex); break; case A1026_SUSPEND: + mutex_lock(&the_vp->mutex); rc = suspend(the_vp); + mutex_unlock(&the_vp->mutex); if (rc < 0) pr_err("suspend error\n"); break; case A1026_ENABLE_CLOCK: pr_debug("%s:ipc clk enable command\n", __func__); + mutex_lock(&the_vp->mutex); rc = intel_sst_set_pll(true, SST_PLL_AUDIENCE); + mutex_unlock(&the_vp->mutex); if (rc) { pr_err("ipc clk enable command failed: %d\n", rc); return rc; @@ -526,7 +548,8 @@ static const struct file_operations a1026_fops = { .release = es305_release, .write = es305_write, .read = es305_read, - .unlocked_ioctl = a1026_ioctl, + .unlocked_ioctl = es305_ioctl, + .llseek = no_llseek, }; static struct miscdevice a1026_device = { @@ -535,12 +558,13 @@ static struct miscdevice a1026_device = { .fops = &a1026_fops, }; -static int a1026_probe( - struct i2c_client *client, const struct i2c_device_id *id) +static int a1026_probe(struct i2c_client *client, + const struct i2c_device_id *id) { int rc; struct vp_ctxt *the_vp; struct a1026_platform_data *pdata; + dev_dbg(&client->dev, "probe\n"); the_vp = kzalloc(sizeof(struct vp_ctxt), GFP_KERNEL); @@ -549,6 +573,7 @@ static int a1026_probe( dev_err(&client->dev, "platform data is out of memory\n"); goto err_exit; } + the_vp->i2c_dev = client; i2c_set_clientdata(client, the_vp); @@ -558,12 +583,14 @@ static int a1026_probe( dev_err(&client->dev, "platform data is invalid\n"); goto err_kfree; } + rc = pdata->request_resources(client); if (rc) { dev_err(&client->dev, "Cannot get ressources\n"); goto err_kfree; } - mutex_init(&a1026_lock); + + mutex_init(&the_vp->mutex); rc = misc_register(&a1026_device); if (rc) { dev_err(&client->dev, "es305_device register failed\n"); @@ -578,7 +605,7 @@ static int a1026_probe( return 0; err_misc_register: - mutex_destroy(&a1026_lock); + mutex_destroy(&the_vp->mutex); err_kfree: kfree(the_vp); i2c_set_clientdata(client, NULL); @@ -589,10 +616,9 @@ err_exit: static int a1026_remove(struct i2c_client *client) { misc_deregister(&a1026_device); - mutex_destroy(&a1026_lock); + mutex_destroy(&es305->mutex); kfree(i2c_get_clientdata(client)); i2c_set_clientdata(client, NULL); - return 0; } diff --git a/include/linux/a1026.h b/include/linux/a1026.h index 2350565..44cd018 100644 --- a/include/linux/a1026.h +++ b/include/linux/a1026.h @@ -72,9 +72,12 @@ enum A1026_config_mode { }; struct a1026_platform_data { + uint32_t gpio_a1026_wakeup; + uint32_t gpio_a1026_reset; int (*request_resources) (struct i2c_client *client); void (*reset) (bool state); void (*wakeup) (bool state); + char firmware_name[128]; };