]> git.karo-electronics.de Git - linux-beck.git/commitdiff
ARM: shmobile: bockw: add R-Car sound support (PIO)
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Mon, 26 Aug 2013 08:52:35 +0000 (01:52 -0700)
committerSimon Horman <horms+renesas@verge.net.au>
Mon, 30 Sep 2013 07:56:11 +0000 (16:56 +0900)
This patch enables R-Car sound,
AK4643 (CN19) and AK4554 (CN20/CN21) codec chip
on Bock-W.

But, it supports PIO transfer only at this point.
User can check sound settings (Dip-switch/PFC etc)
via this patch, but will get under/over flow error
when playback/capture.
Because PIO transfer via SSI will be interrupted
"sampling rate" times per 1 second.

DMA transfer will be supported when HPB-DMAC was
enabled on r8a7778.

You will notice strange ALSA sound card HW
numbering on Bock-W board.
This came from AK4554 strange format on playback/capture.
The format on playback/capture is same on "normal" codec chip,
but AK4554 was different.
Because of that, AK4554 playback/capture are
registered as a different sound card.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
[horms+renesas@verge.net.au: squashed cleanup of SND_SOC_xxx in
 Kconfig by Kuninori Morimoto]
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
arch/arm/mach-shmobile/Kconfig
arch/arm/mach-shmobile/board-bockw.c

index b45240512ce0d6ad288d87133147fba464e98016..d01e4276b88935142b8421ade4316e93eab43f98 100644 (file)
@@ -168,6 +168,8 @@ config MACH_BOCKW
        select RENESAS_INTC_IRQPIN
        select REGULATOR_FIXED_VOLTAGE if REGULATOR
        select USE_OF
+       select SND_SOC_AK4554 if SND_SIMPLE_CARD
+       select SND_SOC_AK4642 if SND_SIMPLE_CARD
 
 config MACH_BOCKW_REFERENCE
        bool "BOCK-W  - Reference Device Tree Implementation"
index b998c6b2a270980c35d6706f6bc15ea83206ef7f..7ad868d0a047f75b9aecef26777ce0448eb3e059 100644 (file)
 #include <mach/irqs.h>
 #include <mach/r8a7778.h>
 #include <asm/mach/arch.h>
+#include <sound/rcar_snd.h>
+#include <sound/simple_card.h>
 
 #define FPGA   0x18200000
 #define IRQ0MR 0x30
+#define COMCTLR        0x101c
 static void __iomem *fpga;
 
 /*
@@ -67,6 +70,35 @@ static void __iomem *fpga;
  * SW19        (MMC)   1 pin
  */
 
+/*
+ *     SSI settings
+ *
+ * SW45: 1-4 side      (SSI5 out, ROUT/LOUT CN19 Mid)
+ * SW46: 1101          (SSI6 Recorde)
+ * SW47: 1110          (SSI5 Playback)
+ * SW48: 11            (Recorde power)
+ * SW49: 1             (SSI slave mode)
+ * SW50: 1111          (SSI7, SSI8)
+ * SW51: 1111          (SSI3, SSI4)
+ * SW54: 1pin          (ak4554 FPGA control)
+ * SW55: 1             (CLKB is 24.5760MHz)
+ * SW60: 1pin          (ak4554 FPGA control)
+ * SW61: 3pin          (use X11 clock)
+ * SW78: 3-6           (ak4642 connects I2C0)
+ *
+ * You can use sound as
+ *
+ * hw0: CN19: SSI56-AK4643
+ * hw1: CN21: SSI3-AK4554(playback)
+ * hw2: CN21: SSI4-AK4554(capture)
+ * hw3: CN20: SSI7-AK4554(playback)
+ * hw4: CN20: SSI8-AK4554(capture)
+ *
+ * this command is required when playback on hw0.
+ *
+ * # amixer set "LINEOUT Mixer DACL" on
+ */
+
 /* Dummy supplies, where voltage doesn't matter */
 static struct regulator_consumer_supply dummy_supplies[] = {
        REGULATOR_SUPPLY("vddvario", "smsc911x"),
@@ -122,7 +154,9 @@ static struct sh_eth_plat_data ether_platform_data __initdata = {
 static struct i2c_board_info i2c0_devices[] = {
        {
                I2C_BOARD_INFO("rx8581", 0x51),
-       },
+       }, {
+               I2C_BOARD_INFO("ak4643", 0x12),
+       }
 };
 
 /* HSPI*/
@@ -185,7 +219,213 @@ static struct soc_camera_link iclink##idx##_ml86v7667 __initdata = {      \
 BOCKW_CAMERA(0);
 BOCKW_CAMERA(1);
 
+/* Sound */
+static struct resource rsnd_resources[] __initdata = {
+       [RSND_GEN1_SRU] = DEFINE_RES_MEM(0xffd90000, 0x1000),
+       [RSND_GEN1_SSI] = DEFINE_RES_MEM(0xffd91000, 0x1240),
+       [RSND_GEN1_ADG] = DEFINE_RES_MEM(0xfffe0000, 0x24),
+};
+
+static struct rsnd_ssi_platform_info rsnd_ssi[] = {
+       RSND_SSI_UNUSED, /* SSI 0 */
+       RSND_SSI_UNUSED, /* SSI 1 */
+       RSND_SSI_UNUSED, /* SSI 2 */
+       RSND_SSI_SET(1, 0, gic_iid(0x85), RSND_SSI_PLAY),
+       RSND_SSI_SET(2, 0, gic_iid(0x85), RSND_SSI_CLK_PIN_SHARE | RSND_SSI_CLK_FROM_ADG),
+       RSND_SSI_SET(0, 0, gic_iid(0x86), RSND_SSI_PLAY),
+       RSND_SSI_SET(0, 0, gic_iid(0x86), 0),
+       RSND_SSI_SET(3, 0, gic_iid(0x86), RSND_SSI_PLAY),
+       RSND_SSI_SET(4, 0, gic_iid(0x86), RSND_SSI_CLK_PIN_SHARE | RSND_SSI_CLK_FROM_ADG),
+};
+
+static struct rsnd_scu_platform_info rsnd_scu[9] = {
+       /* no member at this point */
+};
+
+enum {
+       AK4554_34 = 0,
+       AK4643_56,
+       AK4554_78,
+       SOUND_MAX,
+};
+
+static int rsnd_codec_power(int id, int enable)
+{
+       static int sound_user[SOUND_MAX] = {0, 0, 0};
+       int *usr = NULL;
+       u32 bit;
+
+       switch (id) {
+       case 3:
+       case 4:
+               usr = sound_user + AK4554_34;
+               bit = (1 << 10);
+               break;
+       case 5:
+       case 6:
+               usr = sound_user + AK4643_56;
+               bit = (1 << 6);
+               break;
+       case 7:
+       case 8:
+               usr = sound_user + AK4554_78;
+               bit = (1 << 7);
+               break;
+       }
+
+       if (!usr)
+               return -EIO;
+
+       if (enable) {
+               if (*usr == 0) {
+                       u32 val = ioread16(fpga + COMCTLR);
+                       val &= ~bit;
+                       iowrite16(val, fpga + COMCTLR);
+               }
+
+               (*usr)++;
+       } else {
+               if (*usr == 0)
+                       return 0;
+
+               (*usr)--;
+
+               if (*usr == 0) {
+                       u32 val = ioread16(fpga + COMCTLR);
+                       val |= bit;
+                       iowrite16(val, fpga + COMCTLR);
+               }
+       }
+
+       return 0;
+}
+
+static int rsnd_start(int id)
+{
+       return rsnd_codec_power(id, 1);
+}
+
+static int rsnd_stop(int id)
+{
+       return rsnd_codec_power(id, 0);
+}
+
+static struct rcar_snd_info rsnd_info = {
+       .flags          = RSND_GEN1,
+       .ssi_info       = rsnd_ssi,
+       .ssi_info_nr    = ARRAY_SIZE(rsnd_ssi),
+       .scu_info       = rsnd_scu,
+       .scu_info_nr    = ARRAY_SIZE(rsnd_scu),
+       .start          = rsnd_start,
+       .stop           = rsnd_stop,
+};
+
+static struct asoc_simple_card_info rsnd_card_info[] = {
+       /* SSI5, SSI6 */
+       {
+               .name           = "AK4643",
+               .card           = "SSI56-AK4643",
+               .codec          = "ak4642-codec.0-0012",
+               .platform       = "rcar_sound",
+               .daifmt         = SND_SOC_DAIFMT_LEFT_J,
+               .cpu_dai = {
+                       .name   = "rsnd-dai.0",
+                       .fmt    = SND_SOC_DAIFMT_CBS_CFS,
+               },
+               .codec_dai = {
+                       .name   = "ak4642-hifi",
+                       .fmt    = SND_SOC_DAIFMT_CBM_CFM,
+                       .sysclk = 11289600,
+               },
+       },
+       /* SSI3 */
+       {
+               .name           = "AK4554",
+               .card           = "SSI3-AK4554(playback)",
+               .codec          = "ak4554-adc-dac.0",
+               .platform       = "rcar_sound",
+               .cpu_dai = {
+                       .name   = "rsnd-dai.1",
+                       .fmt    = SND_SOC_DAIFMT_CBM_CFM |
+                                 SND_SOC_DAIFMT_RIGHT_J,
+               },
+               .codec_dai = {
+                       .name   = "ak4554-hifi",
+               },
+       },
+       /* SSI4 */
+       {
+               .name           = "AK4554",
+               .card           = "SSI4-AK4554(capture)",
+               .codec          = "ak4554-adc-dac.0",
+               .platform       = "rcar_sound",
+               .cpu_dai = {
+                       .name   = "rsnd-dai.2",
+                       .fmt    = SND_SOC_DAIFMT_CBM_CFM |
+                                 SND_SOC_DAIFMT_LEFT_J,
+               },
+               .codec_dai = {
+                       .name   = "ak4554-hifi",
+               },
+       },
+       /* SSI7 */
+       {
+               .name           = "AK4554",
+               .card           = "SSI7-AK4554(playback)",
+               .codec          = "ak4554-adc-dac.1",
+               .platform       = "rcar_sound",
+               .cpu_dai = {
+                       .name   = "rsnd-dai.3",
+                       .fmt    = SND_SOC_DAIFMT_CBM_CFM |
+                                 SND_SOC_DAIFMT_RIGHT_J,
+               },
+               .codec_dai = {
+                       .name   = "ak4554-hifi",
+               },
+       },
+       /* SSI8 */
+       {
+               .name           = "AK4554",
+               .card           = "SSI8-AK4554(capture)",
+               .codec          = "ak4554-adc-dac.1",
+               .platform       = "rcar_sound",
+               .cpu_dai = {
+                       .name   = "rsnd-dai.4",
+                       .fmt    = SND_SOC_DAIFMT_CBM_CFM |
+                                 SND_SOC_DAIFMT_LEFT_J,
+               },
+               .codec_dai = {
+                       .name   = "ak4554-hifi",
+               },
+       }
+};
+
 static const struct pinctrl_map bockw_pinctrl_map[] = {
+       /* AUDIO */
+       PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
+                                 "audio_clk_a", "audio_clk"),
+       PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
+                                 "audio_clk_b", "audio_clk"),
+       PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
+                                 "ssi34_ctrl", "ssi"),
+       PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
+                                 "ssi3_data", "ssi"),
+       PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
+                                 "ssi4_data", "ssi"),
+       PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
+                                 "ssi5_ctrl", "ssi"),
+       PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
+                                 "ssi5_data", "ssi"),
+       PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
+                                 "ssi6_ctrl", "ssi"),
+       PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
+                                 "ssi6_data", "ssi"),
+       PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
+                                 "ssi78_ctrl", "ssi"),
+       PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
+                                 "ssi7_data", "ssi"),
+       PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
+                                 "ssi8_data", "ssi"),
        /* Ether */
        PIN_MAP_MUX_GROUP_DEFAULT("r8a777x-ether", "pfc-r8a7778",
                                  "ether_rmii", "ether"),
@@ -233,6 +473,8 @@ static const struct pinctrl_map bockw_pinctrl_map[] = {
 static void __init bockw_init(void)
 {
        void __iomem *base;
+       struct clk *clk;
+       int i;
 
        r8a7778_clock_init();
        r8a7778_init_irq_extpin(1);
@@ -309,6 +551,36 @@ static void __init bockw_init(void)
                        sdhi0_resources, ARRAY_SIZE(sdhi0_resources),
                        &sdhi0_info, sizeof(struct sh_mobile_sdhi_info));
        }
+
+       /* for Audio */
+       clk = clk_get(NULL, "audio_clk_b");
+       clk_set_rate(clk, 24576000);
+       clk_put(clk);
+       rsnd_codec_power(5, 1); /* enable ak4642 */
+
+       platform_device_register_simple(
+               "ak4554-adc-dac", 0, NULL, 0);
+
+       platform_device_register_simple(
+               "ak4554-adc-dac", 1, NULL, 0);
+
+       platform_device_register_resndata(
+               &platform_bus, "rcar_sound", -1,
+               rsnd_resources, ARRAY_SIZE(rsnd_resources),
+               &rsnd_info, sizeof(rsnd_info));
+
+       for (i = 0; i < ARRAY_SIZE(rsnd_card_info); i++) {
+               struct platform_device_info cardinfo = {
+                       .parent         = &platform_bus,
+                       .name           = "asoc-simple-card",
+                       .id             = i,
+                       .data           = &rsnd_card_info[i],
+                       .size_data      = sizeof(struct asoc_simple_card_info),
+                       .dma_mask       = ~0,
+               };
+
+               platform_device_register_full(&cardinfo);
+       }
 }
 
 static const char *bockw_boards_compat_dt[] __initdata = {