asoc: tegra: SPI interface for TI codec
Scott Peterson [Wed, 23 Jan 2013 23:53:01 +0000 (15:53 -0800)]
Add support for accessing the TI aic3262 codec
using the spi interface

Change-Id: I30c72ac2bec5cd51e472f8f4e0750cd533d354a3

Signed-off-by: Scott Peterson <speterson@nvidia.com>
Change-Id: I0dff26133be6c5f0ec36113a61e2b1b5b57b3339
Reviewed-on: http://git-master/r/194172
Tested-by: Vijay Mali <vmali@nvidia.com>
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit

arch/arm/mach-tegra/board-pluto-pinmux-t11x.h
arch/arm/mach-tegra/board-pluto.c
drivers/mfd/tlv320aic3xxx-core.c
drivers/mfd/tlv320aic3xxx-spi.c
sound/soc/tegra/tegra_aic326x.c

index c643f5e..502946e 100644 (file)
@@ -84,11 +84,11 @@ static __initdata struct tegra_pingroup_config pluto_pinmux_common[] = {
        DEFAULT_PINMUX(GMI_WAIT,      DTV,         PULL_DOWN, TRISTATE, INPUT),
 
        /* SPI4 pinmux */
-       DEFAULT_PINMUX(GMI_AD5,       SPI4,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(GMI_AD6,       SPI4,        PULL_UP,   NORMAL,   INPUT),
+       DEFAULT_PINMUX(GMI_AD5,       SPI4,        NORMAL,    NORMAL,   OUTPUT),
+       DEFAULT_PINMUX(GMI_AD6,       SPI4,        PULL_UP,   NORMAL,   OUTPUT),
        DEFAULT_PINMUX(GMI_AD7,       SPI4,        PULL_UP,   NORMAL,   INPUT),
-       DEFAULT_PINMUX(GMI_CS6_N,     SPI4,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(GMI_WR_N,      SPI4,        NORMAL,    NORMAL,   INPUT),
+       DEFAULT_PINMUX(GMI_CS6_N,     SPI4,        PULL_UP,   NORMAL,   OUTPUT),
+       DEFAULT_PINMUX(GMI_WR_N,      SPI4,        PULL_UP,   NORMAL,   OUTPUT),
 
        /* PWM1 pinmux */
        DEFAULT_PINMUX(GMI_AD9,       PWM1,        NORMAL,    NORMAL,   OUTPUT),
index fc10332..54a7b06 100644 (file)
@@ -85,6 +85,7 @@
 #include "pm.h"
 #include "common.h"
 
+
 #ifdef CONFIG_BT_BLUESLEEP
 static struct rfkill_gpio_platform_data pluto_bt_rfkill_pdata = {
        .name           = "bt_rfkill",
@@ -293,9 +294,10 @@ static struct aic3262_gpio_setup aic3262_gpio[] = {
                .in = 0,
                .value = AIC3262_GPIO2_FUNC_ADC_MOD_CLK_OUTPUT,
        },
-       /* GPIO 1 */
+       /* GPI1 */
        {
-               .used = 0,
+               .used = 1,
+               .in = 1,
        },
        /* GPI2 */
        {
@@ -308,8 +310,9 @@ static struct aic3262_gpio_setup aic3262_gpio[] = {
        },
        /* GPO1 */
        {
-               .used = 0,
-               .value = AIC3262_GPO1_FUNC_DISABLED,
+               .used = 1,
+               .in = 0,
+               .value = AIC3262_GPO1_FUNC_MSO_OUTPUT_FOR_SPI,
        },
 };
 static struct aic3xxx_pdata aic3262_codec_pdata = {
@@ -349,7 +352,6 @@ static void pluto_i2c_init(void)
        i2c_register_board_info(0, &pluto_codec_a2220_info, 1);
        i2c_register_board_info(0, &cs42l73_board_info, 1);
        pluto_i2c_bus3_board_info[0].irq = gpio_to_irq(TEGRA_GPIO_PW2);
-       i2c_register_board_info(0, pluto_i2c_bus3_board_info, 1);
        i2c_register_board_info(0, &pluto_codec_aic326x_info, 1);
 }
 
@@ -532,6 +534,25 @@ static struct platform_device pluto_audio_aic326x_device = {
        },
 };
 
+
+static struct tegra_spi_device_controller_data dev_bdata = {
+       .rx_clk_tap_delay = 0,
+       .tx_clk_tap_delay = 0,
+};
+static struct spi_board_info aic326x_spi_board_info[] = {
+       {
+               .modalias = "tlv320aic3xxx",
+               .bus_num = 3,
+               .chip_select = 0,
+               .max_speed_hz = 4*1000*1000,
+               .mode = SPI_MODE_1,
+               .controller_data = &dev_bdata,
+               .platform_data = &aic3262_codec_pdata,
+       },
+};
+
+
+
 #ifdef CONFIG_MHI_NETDEV
 struct platform_device mhi_netdevice0 = {
        .name = "mhi_net_device",
@@ -1002,6 +1023,8 @@ static void pluto_audio_init(void)
 
        tegra_get_board_info(&board_info);
 
+       spi_register_board_info(aic326x_spi_board_info,
+                                       ARRAY_SIZE(aic326x_spi_board_info));
 }
 
 static struct platform_device *pluto_spi_devices[] __initdata = {
index 798e010..d0a7584 100644 (file)
@@ -68,6 +68,11 @@ struct aic3262_gpio aic3262_gpio_control[] = {
         },
 };
 
+/*Codec read count limit once*/
+#define CODEC_BULK_READ_MAX 128
+/*Ap read conut limit once*/
+#define CODEC_BULK_READ_LIMIT 63
+
 int set_aic3xxx_book(struct aic3xxx *aic3xxx, int book)
 {
        int ret = 0;
@@ -157,9 +162,13 @@ int aic3xxx_bulk_read(struct aic3xxx *aic3xxx, unsigned int reg,
                      int count, u8 *buf)
 {
        int ret;
+       int count_temp = count;
        union aic3xxx_reg_union *aic_reg = (union aic3xxx_reg_union *) &reg;
        u8 book, page, offset;
 
+       if (count > CODEC_BULK_READ_MAX)
+               return -1;
+
        page = aic_reg->aic3xxx_register.page;
        book = aic_reg->aic3xxx_register.book;
        offset = aic_reg->aic3xxx_register.offset;
@@ -180,7 +189,23 @@ int aic3xxx_bulk_read(struct aic3xxx *aic3xxx, unsigned int reg,
                        return ret;
                }
        }
-       ret = regmap_bulk_read(aic3xxx->regmap, offset, buf, count);
+
+       while (count_temp) {
+               if (count_temp > CODEC_BULK_READ_LIMIT) {
+                       ret = regmap_bulk_read(aic3xxx->regmap, offset,
+                       buf, CODEC_BULK_READ_LIMIT);
+                       offset += CODEC_BULK_READ_LIMIT;
+                       buf += CODEC_BULK_READ_LIMIT;
+                       count_temp -= CODEC_BULK_READ_LIMIT;
+               } else {
+                       ret = regmap_bulk_read(aic3xxx->regmap, offset,
+                       buf, count_temp);
+                       offset += count_temp;
+                       buf += count_temp;
+                       count_temp -= count_temp;
+               }
+       }
+
        mutex_unlock(&aic3xxx->io_lock);
                return ret;
 }
@@ -332,8 +357,8 @@ int aic3xxx_wait_bits(struct aic3xxx *aic3xxx, unsigned int reg,
        };
        if (!counter)
                dev_err(aic3xxx->dev,
-                       "wait_bits timedout (%d millisecs). lastval 0x%x\n",
-                       timeout, status);
+                       "wait_bits timedout (%d millisecs). lastval 0x%x val 0x%x\n",
+                       timeout, status, val);
        return counter;
 }
 EXPORT_SYMBOL_GPL(aic3xxx_wait_bits);
@@ -416,7 +441,8 @@ int aic3xxx_device_init(struct aic3xxx *aic3xxx, int irq)
                                 aic3xxx->type);
                aic3xxx->type = TLV320AIC3285;
        default:
-               dev_err(aic3xxx->dev, "Device is not a TLV320AIC3262");
+               dev_err(aic3xxx->dev, "Device is not a TLV320AIC3262 type=%d",
+                       ret);
                ret = -EINVAL;
                goto err_return;
        }
@@ -461,6 +487,7 @@ int aic3xxx_device_init(struct aic3xxx *aic3xxx, int irq)
                        aic3xxx_set_bits(aic3xxx, aic3262_gpio_control[i].reg,
                                         aic3262_gpio_control[i].mask, 0x0);
        }
+       aic3xxx->suspended = true;
 
        /* codec interrupt */
        if (aic3xxx->irq) {
index 6f1426a..cd0e506 100644 (file)
 #include <linux/mfd/tlv320aic3xxx-core.h>
 
 struct regmap_config tlv320aic3xxx_spi_regmap = {
-       .reg_bits = 8,
+       .reg_bits = 7,
+       .pad_bits = 1,
        .val_bits = 8,
        .cache_type = REGCACHE_NONE,
        .read_flag_mask = 0x1,
 };
 
+#ifdef CONFIG_PM
+static int aic3xxx_suspend(struct device *dev)
+{
+       struct aic3xxx *aic3xxx = dev_get_drvdata(dev);
+
+       aic3xxx->suspended = true;
+
+       return 0;
+}
+
+static int aic3xxx_resume(struct device *dev)
+{
+       struct aic3xxx *aic3xxx = dev_get_drvdata(dev);
+
+       aic3xxx->suspended = false;
+
+       return 0;
+}
+#endif
+
+
 static int __devinit tlv320aic3xxx_spi_probe(struct spi_device *spi)
 {
        const struct spi_device_id *id = spi_get_device_id(spi);
@@ -24,11 +46,9 @@ static int __devinit tlv320aic3xxx_spi_probe(struct spi_device *spi)
        int ret;
 
        switch (id->driver_data) {
-#ifdef CONFIG_SND_SOC_AIC3262
        case TLV320AIC3262:
                regmap_config = &tlv320aic3xxx_spi_regmap;
                break;
-#endif
 #ifdef CONFIG_MFD_AIC3285
        case TLV320AIC3285:
                regmap_config = &tlv320aic3285_spi_regmap;
@@ -68,16 +88,21 @@ static int __devexit tlv320aic3xxx_spi_remove(struct spi_device *spi)
 }
 
 static const struct spi_device_id aic3xxx_spi_ids[] = {
-       {"tlv320aic3262", TLV320AIC3262},
+       {"tlv320aic3xxx", TLV320AIC3262},
        {"tlv320aic3285", TLV320AIC3285},
        { }
 };
 MODULE_DEVICE_TABLE(spi, aic3xxx_spi_ids);
 
+static UNIVERSAL_DEV_PM_OPS(aic3xxx_pm_ops, aic3xxx_suspend, aic3xxx_resume,
+                               NULL);
+
+
 static struct spi_driver tlv320aic3xxx_spi_driver = {
        .driver = {
                .name   = "tlv320aic3xxx",
                .owner  = THIS_MODULE,
+               .pm     = &aic3xxx_pm_ops,
        },
        .probe          = tlv320aic3xxx_spi_probe,
        .remove         = __devexit_p(tlv320aic3xxx_spi_remove),
index bb7e8e3..215f6e2 100644 (file)
@@ -960,7 +960,7 @@ static int tegra_aic326x_event_int_spk(struct snd_soc_dapm_widget *w,
                return 0;
 
        gpio_set_value_cansleep(pdata->gpio_spkr_en,
-                               SND_SOC_DAPM_EVENT_ON(event));
+                               !!SND_SOC_DAPM_EVENT_ON(event));
 
        return 0;
 }
@@ -1004,7 +1004,7 @@ static int tegra_aic326x_event_dmic(struct snd_soc_dapm_widget *w,
                return 0;
 
        gpio_set_value_cansleep(pdata->gpio_int_mic_en,
-                               SND_SOC_DAPM_EVENT_ON(event));
+                               !!SND_SOC_DAPM_EVENT_ON(event));
 
        return 0;
 }