[alsa-devel] ASoC: ak4642/fsi: add ak4648 support
Dear Mark, Liam, Paul
These are ak4648 suport for ak4642 driver, and fsi update patch set
Kuninori Morimoto (5): ASoC: fsi-ak4642: modify specification method of FSI / ak464x ASoC: ak4642: ak4642 was tested ASoC: ak4642: headphone/stereo-line output control ASoC: ak4642: add ak4648 support ASoC: fsi: add valid data position control support
Paul
Can you please check #1 patch which modify arch/sh and arch/arm
Current fsi-ak4642 was using id_entry name in order to specify FSI port and ak464x codec. But it was no sense, no flexibility. Platform can specify FSI/ak464x pair by this patch.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- arch/arm/mach-shmobile/board-ap4evb.c | 15 ++++- arch/arm/mach-shmobile/board-mackerel.c | 14 ++++- arch/sh/boards/mach-se/7724/setup.c | 14 ++++- include/sound/sh_fsi.h | 12 +++ sound/soc/sh/fsi-ak4642.c | 114 +++---------------------------- 5 files changed, 63 insertions(+), 106 deletions(-)
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 5aa5ddd..5df4e3a 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -787,9 +787,22 @@ static struct platform_device fsi_device = { }, };
+static struct fsi_ak4642_info fsi2_ak4643_info = { + .name = "AK4643", + .card = "FSI2A-AK4643", + .cpu_dai = "fsia-dai", + .codec = "ak4642-codec.0-0013", + .platform = "sh_fsi2", + .id = FSI_PORT_A, +}; + static struct platform_device fsi_ak4643_device = { - .name = "sh_fsi2_a_ak4643", + .name = "fsi-ak4642-audio", + .dev = { + .platform_data = &fsi_info, + }, }; + static struct sh_mobile_meram_cfg hdmi_meram_cfg = { .icb[0] = { .marker_icb = 30, diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index d41c01f..fbef6c8 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -984,8 +984,20 @@ static struct platform_device fsi_device = { }, };
+static struct fsi_ak4642_info fsi2_ak4643_info = { + .name = "AK4643", + .card = "FSI2A-AK4643", + .cpu_dai = "fsia-dai", + .codec = "ak4642-codec.0-0013", + .platform = "sh_fsi2", + .id = FSI_PORT_A, +}; + static struct platform_device fsi_ak4643_device = { - .name = "sh_fsi2_a_ak4643", + .name = "fsi-ak4642-audio", + .dev = { + .platform_data = &fsi2_ak4643_info, + }, };
/* diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index d007567..f56ca9a 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c @@ -315,8 +315,20 @@ static struct platform_device fsi_device = { }, };
+static struct fsi_ak4642_info fsi_ak4642_info = { + .name = "AK4642", + .card = "FSIA-AK4642", + .cpu_dai = "fsia-dai", + .codec = "ak4642-codec.0-0012", + .platform = "sh_fsi.0", + .id = FSI_PORT_A, +}; + static struct platform_device fsi_ak4642_device = { - .name = "sh_fsi_a_ak4642", + .name = "fsi-ak4642-audio", + .dev = { + .platform_data = &fsi_ak4642_info, + }, };
/* KEYSC in SoC (Needs SW33-2 set to ON) */ diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h index 9a155f9..9b1aaca 100644 --- a/include/sound/sh_fsi.h +++ b/include/sound/sh_fsi.h @@ -78,4 +78,16 @@ struct sh_fsi_platform_info { int (*set_rate)(struct device *dev, int is_porta, int rate, int enable); };
+/* + * for fsi-ak4642 + */ +struct fsi_ak4642_info { + const char *name; + const char *card; + const char *cpu_dai; + const char *codec; + const char *platform; + int id; +}; + #endif /* __SOUND_FSI_H */ diff --git a/sound/soc/sh/fsi-ak4642.c b/sound/soc/sh/fsi-ak4642.c index 770a71a..c7d2f8c 100644 --- a/sound/soc/sh/fsi-ak4642.c +++ b/sound/soc/sh/fsi-ak4642.c @@ -57,27 +57,23 @@ static struct platform_device *fsi_snd_device; static int fsi_ak4642_probe(struct platform_device *pdev) { int ret = -ENOMEM; - const struct platform_device_id *id_entry; - struct fsi_ak4642_data *pdata; + struct fsi_ak4642_info *pinfo = pdev->dev.platform_data;
- id_entry = pdev->id_entry; - if (!id_entry) { - dev_err(&pdev->dev, "unknown fsi ak4642\n"); - return -ENODEV; + if (!pinfo) { + dev_err(&pdev->dev, "no info for fsi ak4642\n"); + goto out; }
- pdata = (struct fsi_ak4642_data *)id_entry->driver_data; - - fsi_snd_device = platform_device_alloc("soc-audio", pdata->id); + fsi_snd_device = platform_device_alloc("soc-audio", pinfo->id); if (!fsi_snd_device) goto out;
- fsi_dai_link.name = pdata->name; - fsi_dai_link.stream_name = pdata->name; - fsi_dai_link.cpu_dai_name = pdata->cpu_dai; - fsi_dai_link.platform_name = pdata->platform; - fsi_dai_link.codec_name = pdata->codec; - fsi_soc_card.name = pdata->card; + fsi_dai_link.name = pinfo->name; + fsi_dai_link.stream_name = pinfo->name; + fsi_dai_link.cpu_dai_name = pinfo->cpu_dai; + fsi_dai_link.platform_name = pinfo->platform; + fsi_dai_link.codec_name = pinfo->codec; + fsi_soc_card.name = pinfo->card;
platform_set_drvdata(fsi_snd_device, &fsi_soc_card); ret = platform_device_add(fsi_snd_device); @@ -95,100 +91,12 @@ static int fsi_ak4642_remove(struct platform_device *pdev) return 0; }
-static struct fsi_ak4642_data fsi_a_ak4642 = { - .name = "AK4642", - .card = "FSIA-AK4642", - .cpu_dai = "fsia-dai", - .codec = "ak4642-codec.0-0012", - .platform = "sh_fsi.0", - .id = FSI_PORT_A, -}; - -static struct fsi_ak4642_data fsi_b_ak4642 = { - .name = "AK4642", - .card = "FSIB-AK4642", - .cpu_dai = "fsib-dai", - .codec = "ak4642-codec.0-0012", - .platform = "sh_fsi.0", - .id = FSI_PORT_B, -}; - -static struct fsi_ak4642_data fsi_a_ak4643 = { - .name = "AK4643", - .card = "FSIA-AK4643", - .cpu_dai = "fsia-dai", - .codec = "ak4642-codec.0-0013", - .platform = "sh_fsi.0", - .id = FSI_PORT_A, -}; - -static struct fsi_ak4642_data fsi_b_ak4643 = { - .name = "AK4643", - .card = "FSIB-AK4643", - .cpu_dai = "fsib-dai", - .codec = "ak4642-codec.0-0013", - .platform = "sh_fsi.0", - .id = FSI_PORT_B, -}; - -static struct fsi_ak4642_data fsi2_a_ak4642 = { - .name = "AK4642", - .card = "FSI2A-AK4642", - .cpu_dai = "fsia-dai", - .codec = "ak4642-codec.0-0012", - .platform = "sh_fsi2", - .id = FSI_PORT_A, -}; - -static struct fsi_ak4642_data fsi2_b_ak4642 = { - .name = "AK4642", - .card = "FSI2B-AK4642", - .cpu_dai = "fsib-dai", - .codec = "ak4642-codec.0-0012", - .platform = "sh_fsi2", - .id = FSI_PORT_B, -}; - -static struct fsi_ak4642_data fsi2_a_ak4643 = { - .name = "AK4643", - .card = "FSI2A-AK4643", - .cpu_dai = "fsia-dai", - .codec = "ak4642-codec.0-0013", - .platform = "sh_fsi2", - .id = FSI_PORT_A, -}; - -static struct fsi_ak4642_data fsi2_b_ak4643 = { - .name = "AK4643", - .card = "FSI2B-AK4643", - .cpu_dai = "fsib-dai", - .codec = "ak4642-codec.0-0013", - .platform = "sh_fsi2", - .id = FSI_PORT_B, -}; - -static struct platform_device_id fsi_id_table[] = { - /* FSI */ - { "sh_fsi_a_ak4642", (kernel_ulong_t)&fsi_a_ak4642 }, - { "sh_fsi_b_ak4642", (kernel_ulong_t)&fsi_b_ak4642 }, - { "sh_fsi_a_ak4643", (kernel_ulong_t)&fsi_a_ak4643 }, - { "sh_fsi_b_ak4643", (kernel_ulong_t)&fsi_b_ak4643 }, - - /* FSI 2 */ - { "sh_fsi2_a_ak4642", (kernel_ulong_t)&fsi2_a_ak4642 }, - { "sh_fsi2_b_ak4642", (kernel_ulong_t)&fsi2_b_ak4642 }, - { "sh_fsi2_a_ak4643", (kernel_ulong_t)&fsi2_a_ak4643 }, - { "sh_fsi2_b_ak4643", (kernel_ulong_t)&fsi2_b_ak4643 }, - {}, -}; - static struct platform_driver fsi_ak4642 = { .driver = { .name = "fsi-ak4642-audio", }, .probe = fsi_ak4642_probe, .remove = fsi_ak4642_remove, - .id_table = fsi_id_table, };
static int __init fsi_ak4642_init(void)
Current fsi-ak4642 was using id_entry name in order to specify FSI port and ak464x codec. But it was no sense, no flexibility. Platform can specify FSI/ak464x pair by this patch.
Acked-by: Paul Mundt lethal@linux-sh.org Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- - Mark
This is resend patch. It had been got ack from Paul.
arch/arm/mach-shmobile/board-ap4evb.c | 15 ++++- arch/arm/mach-shmobile/board-mackerel.c | 14 ++++- arch/sh/boards/mach-se/7724/setup.c | 14 ++++- include/sound/sh_fsi.h | 12 +++ sound/soc/sh/fsi-ak4642.c | 114 +++---------------------------- 5 files changed, 63 insertions(+), 106 deletions(-)
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index a3aa0f6..ade98c2 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -762,9 +762,22 @@ static struct platform_device fsi_device = { }, };
+static struct fsi_ak4642_info fsi2_ak4643_info = { + .name = "AK4643", + .card = "FSI2A-AK4643", + .cpu_dai = "fsia-dai", + .codec = "ak4642-codec.0-0013", + .platform = "sh_fsi2", + .id = FSI_PORT_A, +}; + static struct platform_device fsi_ak4643_device = { - .name = "sh_fsi2_a_ak4643", + .name = "fsi-ak4642-audio", + .dev = { + .platform_data = &fsi_info, + }, }; + static struct sh_mobile_meram_cfg hdmi_meram_cfg = { .icb[0] = { .marker_icb = 30, diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 9c5e598..a2908d4 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -990,8 +990,20 @@ static struct platform_device fsi_device = { }, };
+static struct fsi_ak4642_info fsi2_ak4643_info = { + .name = "AK4643", + .card = "FSI2A-AK4643", + .cpu_dai = "fsia-dai", + .codec = "ak4642-codec.0-0013", + .platform = "sh_fsi2", + .id = FSI_PORT_A, +}; + static struct platform_device fsi_ak4643_device = { - .name = "sh_fsi2_a_ak4643", + .name = "fsi-ak4642-audio", + .dev = { + .platform_data = &fsi2_ak4643_info, + }, };
/* diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index b747c0a..b49723b 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c @@ -315,8 +315,20 @@ static struct platform_device fsi_device = { }, };
+static struct fsi_ak4642_info fsi_ak4642_info = { + .name = "AK4642", + .card = "FSIA-AK4642", + .cpu_dai = "fsia-dai", + .codec = "ak4642-codec.0-0012", + .platform = "sh_fsi.0", + .id = FSI_PORT_A, +}; + static struct platform_device fsi_ak4642_device = { - .name = "sh_fsi_a_ak4642", + .name = "fsi-ak4642-audio", + .dev = { + .platform_data = &fsi_ak4642_info, + }, };
/* KEYSC in SoC (Needs SW33-2 set to ON) */ diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h index 9a155f9..9b1aaca 100644 --- a/include/sound/sh_fsi.h +++ b/include/sound/sh_fsi.h @@ -78,4 +78,16 @@ struct sh_fsi_platform_info { int (*set_rate)(struct device *dev, int is_porta, int rate, int enable); };
+/* + * for fsi-ak4642 + */ +struct fsi_ak4642_info { + const char *name; + const char *card; + const char *cpu_dai; + const char *codec; + const char *platform; + int id; +}; + #endif /* __SOUND_FSI_H */ diff --git a/sound/soc/sh/fsi-ak4642.c b/sound/soc/sh/fsi-ak4642.c index dff64b9..11d2d7f 100644 --- a/sound/soc/sh/fsi-ak4642.c +++ b/sound/soc/sh/fsi-ak4642.c @@ -58,27 +58,23 @@ static struct platform_device *fsi_snd_device; static int fsi_ak4642_probe(struct platform_device *pdev) { int ret = -ENOMEM; - const struct platform_device_id *id_entry; - struct fsi_ak4642_data *pdata; + struct fsi_ak4642_info *pinfo = pdev->dev.platform_data;
- id_entry = pdev->id_entry; - if (!id_entry) { - dev_err(&pdev->dev, "unknown fsi ak4642\n"); - return -ENODEV; + if (!pinfo) { + dev_err(&pdev->dev, "no info for fsi ak4642\n"); + goto out; }
- pdata = (struct fsi_ak4642_data *)id_entry->driver_data; - - fsi_snd_device = platform_device_alloc("soc-audio", pdata->id); + fsi_snd_device = platform_device_alloc("soc-audio", pinfo->id); if (!fsi_snd_device) goto out;
- fsi_dai_link.name = pdata->name; - fsi_dai_link.stream_name = pdata->name; - fsi_dai_link.cpu_dai_name = pdata->cpu_dai; - fsi_dai_link.platform_name = pdata->platform; - fsi_dai_link.codec_name = pdata->codec; - fsi_soc_card.name = pdata->card; + fsi_dai_link.name = pinfo->name; + fsi_dai_link.stream_name = pinfo->name; + fsi_dai_link.cpu_dai_name = pinfo->cpu_dai; + fsi_dai_link.platform_name = pinfo->platform; + fsi_dai_link.codec_name = pinfo->codec; + fsi_soc_card.name = pinfo->card;
platform_set_drvdata(fsi_snd_device, &fsi_soc_card); ret = platform_device_add(fsi_snd_device); @@ -96,100 +92,12 @@ static int fsi_ak4642_remove(struct platform_device *pdev) return 0; }
-static struct fsi_ak4642_data fsi_a_ak4642 = { - .name = "AK4642", - .card = "FSIA-AK4642", - .cpu_dai = "fsia-dai", - .codec = "ak4642-codec.0-0012", - .platform = "sh_fsi.0", - .id = FSI_PORT_A, -}; - -static struct fsi_ak4642_data fsi_b_ak4642 = { - .name = "AK4642", - .card = "FSIB-AK4642", - .cpu_dai = "fsib-dai", - .codec = "ak4642-codec.0-0012", - .platform = "sh_fsi.0", - .id = FSI_PORT_B, -}; - -static struct fsi_ak4642_data fsi_a_ak4643 = { - .name = "AK4643", - .card = "FSIA-AK4643", - .cpu_dai = "fsia-dai", - .codec = "ak4642-codec.0-0013", - .platform = "sh_fsi.0", - .id = FSI_PORT_A, -}; - -static struct fsi_ak4642_data fsi_b_ak4643 = { - .name = "AK4643", - .card = "FSIB-AK4643", - .cpu_dai = "fsib-dai", - .codec = "ak4642-codec.0-0013", - .platform = "sh_fsi.0", - .id = FSI_PORT_B, -}; - -static struct fsi_ak4642_data fsi2_a_ak4642 = { - .name = "AK4642", - .card = "FSI2A-AK4642", - .cpu_dai = "fsia-dai", - .codec = "ak4642-codec.0-0012", - .platform = "sh_fsi2", - .id = FSI_PORT_A, -}; - -static struct fsi_ak4642_data fsi2_b_ak4642 = { - .name = "AK4642", - .card = "FSI2B-AK4642", - .cpu_dai = "fsib-dai", - .codec = "ak4642-codec.0-0012", - .platform = "sh_fsi2", - .id = FSI_PORT_B, -}; - -static struct fsi_ak4642_data fsi2_a_ak4643 = { - .name = "AK4643", - .card = "FSI2A-AK4643", - .cpu_dai = "fsia-dai", - .codec = "ak4642-codec.0-0013", - .platform = "sh_fsi2", - .id = FSI_PORT_A, -}; - -static struct fsi_ak4642_data fsi2_b_ak4643 = { - .name = "AK4643", - .card = "FSI2B-AK4643", - .cpu_dai = "fsib-dai", - .codec = "ak4642-codec.0-0013", - .platform = "sh_fsi2", - .id = FSI_PORT_B, -}; - -static struct platform_device_id fsi_id_table[] = { - /* FSI */ - { "sh_fsi_a_ak4642", (kernel_ulong_t)&fsi_a_ak4642 }, - { "sh_fsi_b_ak4642", (kernel_ulong_t)&fsi_b_ak4642 }, - { "sh_fsi_a_ak4643", (kernel_ulong_t)&fsi_a_ak4643 }, - { "sh_fsi_b_ak4643", (kernel_ulong_t)&fsi_b_ak4643 }, - - /* FSI 2 */ - { "sh_fsi2_a_ak4642", (kernel_ulong_t)&fsi2_a_ak4642 }, - { "sh_fsi2_b_ak4642", (kernel_ulong_t)&fsi2_b_ak4642 }, - { "sh_fsi2_a_ak4643", (kernel_ulong_t)&fsi2_a_ak4643 }, - { "sh_fsi2_b_ak4643", (kernel_ulong_t)&fsi2_b_ak4643 }, - {}, -}; - static struct platform_driver fsi_ak4642 = { .driver = { .name = "fsi-ak4642-audio", }, .probe = fsi_ak4642_probe, .remove = fsi_ak4642_remove, - .id_table = fsi_id_table, };
static int __init fsi_ak4642_init(void)
On Wed, Nov 23, 2011 at 04:55:34PM -0800, Kuninori Morimoto wrote:
Current fsi-ak4642 was using id_entry name in order to specify FSI port and ak464x codec. But it was no sense, no flexibility. Platform can specify FSI/ak464x pair by this patch.
Applied, thanks.
ak4642 was tested by ms7724se board
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/codecs/ak4642.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 79c1b3d..50da176 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -18,7 +18,7 @@ * This is very simple driver. * It can use headphone output / stereo input only * - * AK4642 is not tested. + * AK4642 is tested. * AK4643 is tested. */
This patch modifies ak4642 driver to output both headphone/stereo-line in same time.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/codecs/ak4642.c | 44 +++++++++++++++++++++++++++++++++++--------- 1 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 50da176..f30e434 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -75,6 +75,7 @@ /* PW_MGMT1*/ #define PMVCM (1 << 6) /* VCOM Power Management */ #define PMMIN (1 << 5) /* MIN Input Power Management */ +#define PMLO (1 << 3) /* Stereo Line Out Power Management */ #define PMDAC (1 << 2) /* DAC Power Management */ #define PMADL (1 << 0) /* MIC Amp Lch and ADC Lch Power Management */
@@ -98,6 +99,9 @@ #define PMMP (1 << 2) /* MPWR pin Power Management */ #define MGAIN0 (1 << 0) /* MIC amp gain*/
+/* SG_SL2 */ +#define LOPS (1 << 6) /* Stereo Line Output Power-Save Mode */ + /* TIMER */ #define ZTM(param) ((param & 0x3) << 4) /* ALC Zoro Crossing TimeOut */ #define WTM(param) (((param & 0x4) << 4) | ((param & 0x3) << 2)) @@ -130,10 +134,13 @@ #define FS_MASK (FS0 | FS1 | FS2 | FS3)
/* MD_CTL3 */ -#define BST1 (1 << 3) +#define DEM0 (1 << 0) /* De-emphasis Frequency Select */ +#define BST1 (1 << 3) /* Bass Boost Function Select */ +#define DVOLC (1 << 4) /* Output Digital Volume Control Mode Select */
/* MD_CTL4 */ -#define DACH (1 << 0) +#define DACH (1 << 0) /* Switch Control from DAC to Headphone-Amp */ +#define IVOLC (1 << 3) /* Input Digital Volume Control Mode Select */
/* * Playback Volume (table 39) @@ -241,21 +248,31 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
if (is_play) { /* - * start headphone output + * start output + * - headphone + * - stereo line * * PLL, Master Mode * Audio I/F Format :MSB justified (ADC & DAC) - * Bass Boost Level : Middle + * Digital Volume : -8dB + * Bass Boost Level : Middle + * LOVL=MINL bits : 0 * * This operation came from example code of * "ASAHI KASEI AK4642" (japanese) manual p97. + * "ASAHI KASEI AK4642" (japanese) manual p98. + * */ snd_soc_update_bits(codec, MD_CTL4, DACH, DACH); snd_soc_update_bits(codec, MD_CTL3, BST1, BST1); + snd_soc_update_bits(codec, SG_SL1, DACL | MGAIN0, DACL); ak4642_write(codec, L_IVC, 0x91); /* volume */ ak4642_write(codec, R_IVC, 0x91); /* volume */ - snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMMIN | PMDAC, - PMVCM | PMMIN | PMDAC); + snd_soc_update_bits(codec, SG_SL2, LOPS, LOPS); + snd_soc_update_bits(codec, PW_MGMT1, + PMVCM | PMMIN | PMLO | PMDAC, + PMVCM | PMMIN | PMLO | PMDAC); + snd_soc_update_bits(codec, SG_SL2, LOPS, 0); snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP); snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN); } else { @@ -272,7 +289,9 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream, * This operation came from example code of * "ASAHI KASEI AK4642" (japanese) manual p94. */ - ak4642_write(codec, SG_SL1, PMMP | MGAIN0); + snd_soc_update_bits(codec, SG_SL1, + PMMP | MGAIN0, + PMMP | MGAIN0); ak4642_write(codec, TIMER, ZTM(0x3) | WTM(0x3)); ak4642_write(codec, ALC_CTL1, ALC | LMTH0); snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMADL, @@ -290,12 +309,19 @@ static void ak4642_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = dai->codec;
if (is_play) { - /* stop headphone output */ + /* + * stop output + * - headphone + * - stereo line + */ + snd_soc_update_bits(codec, SG_SL2, LOPS, LOPS); snd_soc_update_bits(codec, PW_MGMT2, HPMTN, 0); snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, 0); - snd_soc_update_bits(codec, PW_MGMT1, PMMIN | PMDAC, 0); + snd_soc_update_bits(codec, PW_MGMT1, PMMIN | PMLO | PMDAC, 0); snd_soc_update_bits(codec, MD_CTL3, BST1, 0); snd_soc_update_bits(codec, MD_CTL4, DACH, 0); + snd_soc_update_bits(codec, SG_SL1, DACL, 0); + snd_soc_update_bits(codec, SG_SL2, LOPS, 0); } else { /* stop stereo input */ snd_soc_update_bits(codec, PW_MGMT1, PMADL, 0);
On Sun, Nov 06, 2011 at 10:05:05PM -0800, Kuninori Morimoto wrote:
This patch modifies ak4642 driver to output both headphone/stereo-line in same time.
If you're going to start implementing any sort of routing control you should really be updating the driver to work normally - we shouldn't really have accepted the limited functionality in the first place.
Hi Mark
Thank you for checking patch
This patch modifies ak4642 driver to output both headphone/stereo-line in same time.
If you're going to start implementing any sort of routing control you should really be updating the driver to work normally - we shouldn't really have accepted the limited functionality in the first place.
Sorry. what is this "limited functionality" mean ?
We used headphone output by ak4642/ak4643 on our (old) board. today, our new board use stereo-line output by ak4648.
And ak4642/ak4643/ak4648 can output headphone/stereo-line in same time. I think there is no limited functionality on these chips. but am I misunderstanding ?
Best regards --- Kuninori Morimoto
On Tue, Nov 08, 2011 at 03:22:22AM -0800, Kuninori Morimoto wrote:
If you're going to start implementing any sort of routing control you should really be updating the driver to work normally - we shouldn't really have accepted the limited functionality in the first place.
Sorry. what is this "limited functionality" mean ?
Your driver is using hard coded paths rather than offering the user runtime control of the audio routing.
This patch adds ak4648 support. ak4642/ak4643/ak4648 are register compatible, but these have a slightly different register default value. struct ak4642_chip is added in order to absorb this difference.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/codecs/ak4642.c | 74 +++++++++++++++++++++++++++++++++++++++----- 1 files changed, 65 insertions(+), 9 deletions(-)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index f30e434..1b768ad 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -20,6 +20,7 @@ * * AK4642 is tested. * AK4643 is tested. + * AK4648 is tested. */
#include <linux/delay.h> @@ -70,8 +71,6 @@ #define HP_MS 0x23 #define SPK_MS 0x24
-#define AK4642_CACHEREGNUM 0x25 - /* PW_MGMT1*/ #define PMVCM (1 << 6) /* VCOM Power Management */ #define PMMIN (1 << 5) /* MIN Input Power Management */ @@ -158,28 +157,58 @@ static const struct snd_kcontrol_new ak4642_snd_controls[] = { 0, 0xFF, 1, out_tlv), };
+/* + * ak464x list + */ + +#define AK4642_CACHEREGNUM (0x24 + 1) +#define AK4648_CACHEREGNUM (0x27 + 1) +#define AK464x_CACHEREGNUM_MAX AK4648_CACHEREGNUM /* max size */
/* codec private data */ +struct ak4642_reg_fix { + unsigned int reg; + unsigned int val; +}; + +struct ak4642_chip { + int reg_max; + struct ak4642_reg_fix *reg_fix; + int reg_fix_size; +}; + struct ak4642_priv { unsigned int sysclk; enum snd_soc_control_type control_type; void *control_data; + struct ak4642_chip *chip; };
/* * ak4642 register cache */ -static const u8 ak4642_reg[AK4642_CACHEREGNUM] = { +static const u8 ak4642_reg[AK464x_CACHEREGNUM_MAX] = { 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0xe1, 0xe1, 0x18, 0x00, - 0xe1, 0x18, 0x11, 0x08, + 0xe1, 0x18, 0x11, 0xff, /* 0xF will be fixed */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, + 0x00, 0xff, 0xff, 0xff, /* 0x25 - 0x27 will be fixed */ +}; + +static struct ak4642_reg_fix ak4642_reg_fix[] = { + { 0xF, 0x08 } +}; + +static struct ak4642_reg_fix ak4648_reg_fix[] = { + { 0xF, 0xb8 }, + { 0x25, 0x88 }, + { 0x26, 0x88 }, + { 0x27, 0x08 }, };
/* @@ -496,6 +525,8 @@ static int ak4642_resume(struct snd_soc_codec *codec) static int ak4642_probe(struct snd_soc_codec *codec) { struct ak4642_priv *ak4642 = snd_soc_codec_get_drvdata(codec); + struct ak4642_chip *chip = ak4642->chip; + int i;
dev_info(codec->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
@@ -505,6 +536,15 @@ static int ak4642_probe(struct snd_soc_codec *codec) snd_soc_add_controls(codec, ak4642_snd_controls, ARRAY_SIZE(ak4642_snd_controls));
+ /* + * fixup register cache + * each ak464x have a slightly different value + */ + for (i = 0; i < chip->reg_fix_size; i++) + ak4642_write_reg_cache(codec, + chip->reg_fix[i].reg, + chip->reg_fix[i].val); + return 0; }
@@ -530,8 +570,9 @@ static __devinit int ak4642_i2c_probe(struct i2c_client *i2c, return -ENOMEM;
i2c_set_clientdata(i2c, ak4642); - ak4642->control_data = i2c; - ak4642->control_type = SND_SOC_I2C; + ak4642->control_data = i2c; + ak4642->control_type = SND_SOC_I2C; + ak4642->chip = (struct ak4642_chip *)id->driver_data;
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_ak4642, &ak4642_dai, 1); @@ -547,9 +588,24 @@ static __devexit int ak4642_i2c_remove(struct i2c_client *client) return 0; }
+/* ak4642 / ak4643 */ +static const struct ak4642_chip ak4642_chip = { + .reg_max = AK4642_CACHEREGNUM, + .reg_fix = ak4642_reg_fix, + .reg_fix_size = ARRAY_SIZE(ak4642_reg_fix), +}; + +/* ak4648 */ +static const struct ak4642_chip ak4648_chip = { + .reg_max = AK4648_CACHEREGNUM, + .reg_fix = ak4648_reg_fix, + .reg_fix_size = ARRAY_SIZE(ak4648_reg_fix), +}; + static const struct i2c_device_id ak4642_i2c_id[] = { - { "ak4642", 0 }, - { "ak4643", 0 }, + { "ak4642", (kernel_ulong_t)&ak4642_chip }, + { "ak4643", (kernel_ulong_t)&ak4642_chip }, /* same as ak4642 */ + { "ak4648", (kernel_ulong_t)&ak4648_chip }, { } }; MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);
On Sun, Nov 06, 2011 at 10:05:15PM -0800, Kuninori Morimoto wrote:
+#define AK4642_CACHEREGNUM (0x24 + 1) +#define AK4648_CACHEREGNUM (0x27 + 1)
- /*
* fixup register cache
* each ak464x have a slightly different value
*/
- for (i = 0; i < chip->reg_fix_size; i++)
ak4642_write_reg_cache(codec,
chip->reg_fix[i].reg,
chip->reg_fix[i].val);
This won't work properly when resyncing the cache as the driver will think that these are non-default values. Given how small the register maps are just have different default tables, it's not worth the effort of doing anything more complex.
FSI2 can control valid data position, like package in front/back or stream mode (16bit x 2). But current fsi driver is assuming it was in-back.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/fsi.c | 15 +++++++++++++++ 1 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 8e112cc..4bfc372 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -31,7 +31,9 @@ #define REG_DIDT 0x0020 #define REG_DODT 0x0024 #define REG_MUTE_ST 0x0028 +#define REG_OUT_DMAC 0x002C #define REG_OUT_SEL 0x0030 +#define REG_IN_DMAC 0x0038
/* master register */ #define MST_CLK_RST 0x0210 @@ -885,6 +887,8 @@ static int fsi_hw_startup(struct fsi_priv *fsi, int is_play, struct device *dev) { + struct fsi_master *master = fsi_get_master(fsi); + int fsi_ver = master->core->ver; u32 flags = fsi_get_info_flags(fsi); u32 data = 0;
@@ -919,6 +923,17 @@ static int fsi_hw_startup(struct fsi_priv *fsi, fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD); }
+ /* + * FIXME + * + * FSI driver assumed that data package is in-back. + * FSI2 chip can select it. + */ + if (fsi_ver >= 2) { + fsi_reg_write(fsi, OUT_DMAC, (1 << 4)); + fsi_reg_write(fsi, IN_DMAC, (1 << 4)); + } + /* irq clear */ fsi_irq_disable(fsi, is_play); fsi_irq_clear_status(fsi);
On Sun, Nov 06, 2011 at 10:05:25PM -0800, Kuninori Morimoto wrote:
FSI2 can control valid data position, like package in front/back or stream mode (16bit x 2). But current fsi driver is assuming it was in-back.
Applied, thanks.
Hi Mark, Liam
These are redo of below patches
ASoC: ak4642: headphone/stereo-line output control ASoC: ak4642: add ak4648 support
Kuninori Morimoto (5): ASoC: ak4642: add ak4642_set_bias_level() ASoC: ak4642: add DAPM support for HeadPhone Output ASoC: ak4642: add headphone mute switch control ASoC: ak4642: add Line out support ASoC: ak4642: add ak4648 support
This time I tried to use DAPM for "Output". I will try "Input" case in the future
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/codecs/ak4642.c | 31 +++++++++++++++++++++++++++---- 1 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index b854eb0..eaf064a 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -196,8 +196,8 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream, snd_soc_update_bits(codec, MD_CTL3, BST1, BST1); snd_soc_write(codec, L_IVC, 0x91); /* volume */ snd_soc_write(codec, R_IVC, 0x91); /* volume */ - snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMMIN | PMDAC, - PMVCM | PMMIN | PMDAC); + snd_soc_update_bits(codec, PW_MGMT1, PMMIN | PMDAC, + PMMIN | PMDAC); snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP); snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN); } else { @@ -217,8 +217,7 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream, snd_soc_write(codec, SG_SL1, PMMP | MGAIN0); snd_soc_write(codec, TIMER, ZTM(0x3) | WTM(0x3)); snd_soc_write(codec, ALC_CTL1, ALC | LMTH0); - snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMADL, - PMVCM | PMADL); + snd_soc_update_bits(codec, PW_MGMT1, PMADL, PMADL); snd_soc_update_bits(codec, PW_MGMT3, PMADR, PMADR); }
@@ -376,6 +375,20 @@ static int ak4642_dai_hw_params(struct snd_pcm_substream *substream, return 0; }
+static int ak4642_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_OFF: + snd_soc_write(codec, PW_MGMT1, 0x00); + break; + default: + snd_soc_update_bits(codec, PW_MGMT1, PMVCM, PMVCM); + } + codec->dapm.bias_level = level; + return 0; +} + static struct snd_soc_dai_ops ak4642_dai_ops = { .startup = ak4642_dai_startup, .shutdown = ak4642_dai_shutdown, @@ -425,12 +438,22 @@ static int ak4642_probe(struct snd_soc_codec *codec) snd_soc_add_controls(codec, ak4642_snd_controls, ARRAY_SIZE(ak4642_snd_controls));
+ ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + return 0; +} + +static int ak4642_remove(struct snd_soc_codec *codec) +{ + ak4642_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; }
static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { .probe = ak4642_probe, + .remove = ak4642_remove, .resume = ak4642_resume, + .set_bias_level = ak4642_set_bias_level, .reg_cache_size = ARRAY_SIZE(ak4642_reg), .reg_word_size = sizeof(u8), .reg_cache_default = ak4642_reg,
On Thu, Nov 10, 2011 at 12:21:13AM -0800, Kuninori Morimoto wrote:
- switch (level) {
- case SND_SOC_BIAS_OFF:
snd_soc_write(codec, PW_MGMT1, 0x00);
break;
- default:
snd_soc_update_bits(codec, PW_MGMT1, PMVCM, PMVCM);
- }
Should have a break; here for coding style.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/codecs/ak4642.c | 44 +++++++++++++++++++++++++++++++++++--------- 1 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index eaf064a..8aa9dd1 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -152,6 +152,37 @@ static const struct snd_kcontrol_new ak4642_snd_controls[] = { 0, 0xFF, 1, out_tlv), };
+static const struct snd_kcontrol_new ak4642_hpout_mixer_controls[] = { + SOC_DAPM_SINGLE("DACH", MD_CTL4, 0, 1, 0), +}; + +static const struct snd_soc_dapm_widget ak4642_dapm_widgets[] = { + + /* Outputs */ + SND_SOC_DAPM_OUTPUT("HPOUTL"), + SND_SOC_DAPM_OUTPUT("HPOUTR"), + + SND_SOC_DAPM_MIXER("HPOUTL Mixer", PW_MGMT2, 5, 0, + &ak4642_hpout_mixer_controls[0], + ARRAY_SIZE(ak4642_hpout_mixer_controls)), + + SND_SOC_DAPM_MIXER("HPOUTR Mixer", PW_MGMT2, 4, 0, + &ak4642_hpout_mixer_controls[0], + ARRAY_SIZE(ak4642_hpout_mixer_controls)), + + /* DAC */ + SND_SOC_DAPM_DAC("DAC", "HiFi Playback", PW_MGMT1, 2, 0), +}; + +static const struct snd_soc_dapm_route ak4642_intercon[] = { + + /* Outputs */ + {"HPOUTL", "NULL", "HPOUTL Mixer"}, + {"HPOUTR", "NULL", "HPOUTR Mixer"}, + + {"HPOUTL Mixer", "DACH", "DAC"}, + {"HPOUTR Mixer", "DACH", "DAC"}, +};
/* codec private data */ struct ak4642_priv { @@ -192,13 +223,8 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream, * This operation came from example code of * "ASAHI KASEI AK4642" (japanese) manual p97. */ - snd_soc_update_bits(codec, MD_CTL4, DACH, DACH); - snd_soc_update_bits(codec, MD_CTL3, BST1, BST1); snd_soc_write(codec, L_IVC, 0x91); /* volume */ snd_soc_write(codec, R_IVC, 0x91); /* volume */ - snd_soc_update_bits(codec, PW_MGMT1, PMMIN | PMDAC, - PMMIN | PMDAC); - snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP); snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN); } else { /* @@ -233,10 +259,6 @@ static void ak4642_dai_shutdown(struct snd_pcm_substream *substream, if (is_play) { /* stop headphone output */ snd_soc_update_bits(codec, PW_MGMT2, HPMTN, 0); - snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, 0); - snd_soc_update_bits(codec, PW_MGMT1, PMMIN | PMDAC, 0); - snd_soc_update_bits(codec, MD_CTL3, BST1, 0); - snd_soc_update_bits(codec, MD_CTL4, DACH, 0); } else { /* stop stereo input */ snd_soc_update_bits(codec, PW_MGMT1, PMADL, 0); @@ -457,6 +479,10 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { .reg_cache_size = ARRAY_SIZE(ak4642_reg), .reg_word_size = sizeof(u8), .reg_cache_default = ak4642_reg, + .dapm_widgets = ak4642_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4642_dapm_widgets), + .dapm_routes = ak4642_intercon, + .num_dapm_routes = ARRAY_SIZE(ak4642_intercon), };
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/codecs/ak4642.c | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 8aa9dd1..473202a 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -150,6 +150,8 @@ static const struct snd_kcontrol_new ak4642_snd_controls[] = {
SOC_DOUBLE_R_TLV("Digital Playback Volume", L_DVC, R_DVC, 0, 0xFF, 1, out_tlv), + + SOC_SINGLE("Headphone Mute Switch", PW_MGMT2, 6, 1, 0), };
static const struct snd_kcontrol_new ak4642_hpout_mixer_controls[] = { @@ -225,7 +227,6 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream, */ snd_soc_write(codec, L_IVC, 0x91); /* volume */ snd_soc_write(codec, R_IVC, 0x91); /* volume */ - snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN); } else { /* * start stereo input @@ -257,8 +258,6 @@ static void ak4642_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = dai->codec;
if (is_play) { - /* stop headphone output */ - snd_soc_update_bits(codec, PW_MGMT2, HPMTN, 0); } else { /* stop stereo input */ snd_soc_update_bits(codec, PW_MGMT1, PMADL, 0);
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/codecs/ak4642.c | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 473202a..8b32f41 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -158,11 +158,16 @@ static const struct snd_kcontrol_new ak4642_hpout_mixer_controls[] = { SOC_DAPM_SINGLE("DACH", MD_CTL4, 0, 1, 0), };
+static const struct snd_kcontrol_new ak4642_lout_mixer_controls[] = { + SOC_DAPM_SINGLE("DACL", SG_SL1, 4, 1, 0), +}; + static const struct snd_soc_dapm_widget ak4642_dapm_widgets[] = {
/* Outputs */ SND_SOC_DAPM_OUTPUT("HPOUTL"), SND_SOC_DAPM_OUTPUT("HPOUTR"), + SND_SOC_DAPM_OUTPUT("LINEOUT"),
SND_SOC_DAPM_MIXER("HPOUTL Mixer", PW_MGMT2, 5, 0, &ak4642_hpout_mixer_controls[0], @@ -172,6 +177,10 @@ static const struct snd_soc_dapm_widget ak4642_dapm_widgets[] = { &ak4642_hpout_mixer_controls[0], ARRAY_SIZE(ak4642_hpout_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LINEOUT Mixer", PW_MGMT1, 3, 0, + &ak4642_lout_mixer_controls[0], + ARRAY_SIZE(ak4642_lout_mixer_controls)), + /* DAC */ SND_SOC_DAPM_DAC("DAC", "HiFi Playback", PW_MGMT1, 2, 0), }; @@ -181,9 +190,12 @@ static const struct snd_soc_dapm_route ak4642_intercon[] = { /* Outputs */ {"HPOUTL", "NULL", "HPOUTL Mixer"}, {"HPOUTR", "NULL", "HPOUTR Mixer"}, + {"LINEOUT", "NULL", "LINEOUT Mixer"},
{"HPOUTL Mixer", "DACH", "DAC"}, {"HPOUTR Mixer", "DACH", "DAC"}, + {"LINEOUT Mixer", "DACL", "DAC"}, + };
/* codec private data */
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/codecs/ak4642.c | 44 ++++++++++++++++++++++++++++++++++++-------- 1 files changed, 36 insertions(+), 8 deletions(-)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 8b32f41..b7b650a 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -20,6 +20,7 @@ * * AK4642 is tested. * AK4643 is tested. + * AK4648 is tested. */
#include <linux/delay.h> @@ -71,8 +72,6 @@ #define HP_MS 0x23 #define SPK_MS 0x24
-#define AK4642_CACHEREGNUM 0x25 - /* PW_MGMT1*/ #define PMVCM (1 << 6) /* VCOM Power Management */ #define PMMIN (1 << 5) /* MIN Input Power Management */ @@ -207,7 +206,7 @@ struct ak4642_priv { /* * ak4642 register cache */ -static const u8 ak4642_reg[AK4642_CACHEREGNUM] = { +static const u8 ak4642_reg[] = { 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0xe1, 0xe1, 0x18, 0x00, @@ -220,6 +219,19 @@ static const u8 ak4642_reg[AK4642_CACHEREGNUM] = { 0x00, };
+static const u8 ak4648_reg[] = { + 0x00, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x00, 0x00, + 0xe1, 0xe1, 0x18, 0x00, + 0xe1, 0x18, 0x11, 0xb8, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x88, 0x88, 0x08, +}; + static int ak4642_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -487,9 +499,23 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { .remove = ak4642_remove, .resume = ak4642_resume, .set_bias_level = ak4642_set_bias_level, - .reg_cache_size = ARRAY_SIZE(ak4642_reg), + .reg_cache_default = ak4642_reg, /* ak4642 reg */ + .reg_cache_size = ARRAY_SIZE(ak4642_reg), /* ak4642 reg */ + .reg_word_size = sizeof(u8), + .dapm_widgets = ak4642_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4642_dapm_widgets), + .dapm_routes = ak4642_intercon, + .num_dapm_routes = ARRAY_SIZE(ak4642_intercon), +}; + +static struct snd_soc_codec_driver soc_codec_dev_ak4648 = { + .probe = ak4642_probe, + .remove = ak4642_remove, + .resume = ak4642_resume, + .set_bias_level = ak4642_set_bias_level, + .reg_cache_default = ak4648_reg, /* ak4648 reg */ + .reg_cache_size = ARRAY_SIZE(ak4648_reg), /* ak4648 reg */ .reg_word_size = sizeof(u8), - .reg_cache_default = ak4642_reg, .dapm_widgets = ak4642_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(ak4642_dapm_widgets), .dapm_routes = ak4642_intercon, @@ -511,7 +537,8 @@ static __devinit int ak4642_i2c_probe(struct i2c_client *i2c, ak4642->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c->dev, - &soc_codec_dev_ak4642, &ak4642_dai, 1); + (struct snd_soc_codec_driver *)id->driver_data, + &ak4642_dai, 1); if (ret < 0) kfree(ak4642); return ret; @@ -525,8 +552,9 @@ static __devexit int ak4642_i2c_remove(struct i2c_client *client) }
static const struct i2c_device_id ak4642_i2c_id[] = { - { "ak4642", 0 }, - { "ak4643", 0 }, + { "ak4642", (kernel_ulong_t)&soc_codec_dev_ak4642 }, + { "ak4643", (kernel_ulong_t)&soc_codec_dev_ak4642 }, + { "ak4648", (kernel_ulong_t)&soc_codec_dev_ak4648 }, { } }; MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);
Hi Mark, Liam
This time I tried to use DAPM for "Output". I will try "Input" case in the future
This looks mostly good, a couple of minor coments but nothing major.
Thank you. These are v2 patch set
Kuninori Morimoto (5): ASoC: ak4642: add ak4642_set_bias_level() ASoC: ak4642: add DAPM support for HeadPhone Output ASoC: ak4642: add headphone mute switch control ASoC: ak4642: add Line out support ASoC: ak4642: add ak4648 support
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- v1 -> v2
- add break; for switch default case
sound/soc/codecs/ak4642.c | 33 +++++++++++++++++++++++++++++---- 1 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index b854eb0..004a093 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -196,8 +196,8 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream, snd_soc_update_bits(codec, MD_CTL3, BST1, BST1); snd_soc_write(codec, L_IVC, 0x91); /* volume */ snd_soc_write(codec, R_IVC, 0x91); /* volume */ - snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMMIN | PMDAC, - PMVCM | PMMIN | PMDAC); + snd_soc_update_bits(codec, PW_MGMT1, PMMIN | PMDAC, + PMMIN | PMDAC); snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP); snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN); } else { @@ -217,8 +217,7 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream, snd_soc_write(codec, SG_SL1, PMMP | MGAIN0); snd_soc_write(codec, TIMER, ZTM(0x3) | WTM(0x3)); snd_soc_write(codec, ALC_CTL1, ALC | LMTH0); - snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMADL, - PMVCM | PMADL); + snd_soc_update_bits(codec, PW_MGMT1, PMADL, PMADL); snd_soc_update_bits(codec, PW_MGMT3, PMADR, PMADR); }
@@ -376,6 +375,22 @@ static int ak4642_dai_hw_params(struct snd_pcm_substream *substream, return 0; }
+static int ak4642_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_OFF: + snd_soc_write(codec, PW_MGMT1, 0x00); + break; + default: + snd_soc_update_bits(codec, PW_MGMT1, PMVCM, PMVCM); + break; + } + codec->dapm.bias_level = level; + + return 0; +} + static struct snd_soc_dai_ops ak4642_dai_ops = { .startup = ak4642_dai_startup, .shutdown = ak4642_dai_shutdown, @@ -425,12 +440,22 @@ static int ak4642_probe(struct snd_soc_codec *codec) snd_soc_add_controls(codec, ak4642_snd_controls, ARRAY_SIZE(ak4642_snd_controls));
+ ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + return 0; +} + +static int ak4642_remove(struct snd_soc_codec *codec) +{ + ak4642_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; }
static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { .probe = ak4642_probe, + .remove = ak4642_remove, .resume = ak4642_resume, + .set_bias_level = ak4642_set_bias_level, .reg_cache_size = ARRAY_SIZE(ak4642_reg), .reg_word_size = sizeof(u8), .reg_cache_default = ak4642_reg,
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- v1 -> v2
- same as v1
sound/soc/codecs/ak4642.c | 44 +++++++++++++++++++++++++++++++++++--------- 1 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 004a093..da9caf0 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -152,6 +152,37 @@ static const struct snd_kcontrol_new ak4642_snd_controls[] = { 0, 0xFF, 1, out_tlv), };
+static const struct snd_kcontrol_new ak4642_hpout_mixer_controls[] = { + SOC_DAPM_SINGLE("DACH", MD_CTL4, 0, 1, 0), +}; + +static const struct snd_soc_dapm_widget ak4642_dapm_widgets[] = { + + /* Outputs */ + SND_SOC_DAPM_OUTPUT("HPOUTL"), + SND_SOC_DAPM_OUTPUT("HPOUTR"), + + SND_SOC_DAPM_MIXER("HPOUTL Mixer", PW_MGMT2, 5, 0, + &ak4642_hpout_mixer_controls[0], + ARRAY_SIZE(ak4642_hpout_mixer_controls)), + + SND_SOC_DAPM_MIXER("HPOUTR Mixer", PW_MGMT2, 4, 0, + &ak4642_hpout_mixer_controls[0], + ARRAY_SIZE(ak4642_hpout_mixer_controls)), + + /* DAC */ + SND_SOC_DAPM_DAC("DAC", "HiFi Playback", PW_MGMT1, 2, 0), +}; + +static const struct snd_soc_dapm_route ak4642_intercon[] = { + + /* Outputs */ + {"HPOUTL", NULL, "HPOUTL Mixer"}, + {"HPOUTR", NULL, "HPOUTR Mixer"}, + + {"HPOUTL Mixer", "DACH", "DAC"}, + {"HPOUTR Mixer", "DACH", "DAC"}, +};
/* codec private data */ struct ak4642_priv { @@ -192,13 +223,8 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream, * This operation came from example code of * "ASAHI KASEI AK4642" (japanese) manual p97. */ - snd_soc_update_bits(codec, MD_CTL4, DACH, DACH); - snd_soc_update_bits(codec, MD_CTL3, BST1, BST1); snd_soc_write(codec, L_IVC, 0x91); /* volume */ snd_soc_write(codec, R_IVC, 0x91); /* volume */ - snd_soc_update_bits(codec, PW_MGMT1, PMMIN | PMDAC, - PMMIN | PMDAC); - snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP); snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN); } else { /* @@ -233,10 +259,6 @@ static void ak4642_dai_shutdown(struct snd_pcm_substream *substream, if (is_play) { /* stop headphone output */ snd_soc_update_bits(codec, PW_MGMT2, HPMTN, 0); - snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, 0); - snd_soc_update_bits(codec, PW_MGMT1, PMMIN | PMDAC, 0); - snd_soc_update_bits(codec, MD_CTL3, BST1, 0); - snd_soc_update_bits(codec, MD_CTL4, DACH, 0); } else { /* stop stereo input */ snd_soc_update_bits(codec, PW_MGMT1, PMADL, 0); @@ -459,6 +481,10 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { .reg_cache_size = ARRAY_SIZE(ak4642_reg), .reg_word_size = sizeof(u8), .reg_cache_default = ak4642_reg, + .dapm_widgets = ak4642_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4642_dapm_widgets), + .dapm_routes = ak4642_intercon, + .num_dapm_routes = ARRAY_SIZE(ak4642_intercon), };
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- v1 -> v2
- "Headphone Mute Switch" -> "Headphone Switch"
sound/soc/codecs/ak4642.c | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index da9caf0..b2460c2 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -150,6 +150,8 @@ static const struct snd_kcontrol_new ak4642_snd_controls[] = {
SOC_DOUBLE_R_TLV("Digital Playback Volume", L_DVC, R_DVC, 0, 0xFF, 1, out_tlv), + + SOC_SINGLE("Headphone Switch", PW_MGMT2, 6, 1, 0), };
static const struct snd_kcontrol_new ak4642_hpout_mixer_controls[] = { @@ -225,7 +227,6 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream, */ snd_soc_write(codec, L_IVC, 0x91); /* volume */ snd_soc_write(codec, R_IVC, 0x91); /* volume */ - snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN); } else { /* * start stereo input @@ -257,8 +258,6 @@ static void ak4642_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = dai->codec;
if (is_play) { - /* stop headphone output */ - snd_soc_update_bits(codec, PW_MGMT2, HPMTN, 0); } else { /* stop stereo input */ snd_soc_update_bits(codec, PW_MGMT1, PMADL, 0);
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- v1 -> v2
- same as v1
sound/soc/codecs/ak4642.c | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index b2460c2..daec5f75d 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -158,11 +158,16 @@ static const struct snd_kcontrol_new ak4642_hpout_mixer_controls[] = { SOC_DAPM_SINGLE("DACH", MD_CTL4, 0, 1, 0), };
+static const struct snd_kcontrol_new ak4642_lout_mixer_controls[] = { + SOC_DAPM_SINGLE("DACL", SG_SL1, 4, 1, 0), +}; + static const struct snd_soc_dapm_widget ak4642_dapm_widgets[] = {
/* Outputs */ SND_SOC_DAPM_OUTPUT("HPOUTL"), SND_SOC_DAPM_OUTPUT("HPOUTR"), + SND_SOC_DAPM_OUTPUT("LINEOUT"),
SND_SOC_DAPM_MIXER("HPOUTL Mixer", PW_MGMT2, 5, 0, &ak4642_hpout_mixer_controls[0], @@ -172,6 +177,10 @@ static const struct snd_soc_dapm_widget ak4642_dapm_widgets[] = { &ak4642_hpout_mixer_controls[0], ARRAY_SIZE(ak4642_hpout_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LINEOUT Mixer", PW_MGMT1, 3, 0, + &ak4642_lout_mixer_controls[0], + ARRAY_SIZE(ak4642_lout_mixer_controls)), + /* DAC */ SND_SOC_DAPM_DAC("DAC", "HiFi Playback", PW_MGMT1, 2, 0), }; @@ -181,9 +190,11 @@ static const struct snd_soc_dapm_route ak4642_intercon[] = { /* Outputs */ {"HPOUTL", NULL, "HPOUTL Mixer"}, {"HPOUTR", NULL, "HPOUTR Mixer"}, + {"LINEOUT", NULL, "LINEOUT Mixer"},
{"HPOUTL Mixer", "DACH", "DAC"}, {"HPOUTR Mixer", "DACH", "DAC"}, + {"LINEOUT Mixer", "DACL", "DAC"}, };
/* codec private data */
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- v1 -> v2
- same as v1
sound/soc/codecs/ak4642.c | 44 ++++++++++++++++++++++++++++++++++++-------- 1 files changed, 36 insertions(+), 8 deletions(-)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index daec5f75d..859e015 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -20,6 +20,7 @@ * * AK4642 is tested. * AK4643 is tested. + * AK4648 is tested. */
#include <linux/delay.h> @@ -71,8 +72,6 @@ #define HP_MS 0x23 #define SPK_MS 0x24
-#define AK4642_CACHEREGNUM 0x25 - /* PW_MGMT1*/ #define PMVCM (1 << 6) /* VCOM Power Management */ #define PMMIN (1 << 5) /* MIN Input Power Management */ @@ -206,7 +205,7 @@ struct ak4642_priv { /* * ak4642 register cache */ -static const u8 ak4642_reg[AK4642_CACHEREGNUM] = { +static const u8 ak4642_reg[] = { 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0xe1, 0xe1, 0x18, 0x00, @@ -219,6 +218,19 @@ static const u8 ak4642_reg[AK4642_CACHEREGNUM] = { 0x00, };
+static const u8 ak4648_reg[] = { + 0x00, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x00, 0x00, + 0xe1, 0xe1, 0x18, 0x00, + 0xe1, 0x18, 0x11, 0xb8, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x88, 0x88, 0x08, +}; + static int ak4642_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -488,9 +500,23 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { .remove = ak4642_remove, .resume = ak4642_resume, .set_bias_level = ak4642_set_bias_level, - .reg_cache_size = ARRAY_SIZE(ak4642_reg), + .reg_cache_default = ak4642_reg, /* ak4642 reg */ + .reg_cache_size = ARRAY_SIZE(ak4642_reg), /* ak4642 reg */ + .reg_word_size = sizeof(u8), + .dapm_widgets = ak4642_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4642_dapm_widgets), + .dapm_routes = ak4642_intercon, + .num_dapm_routes = ARRAY_SIZE(ak4642_intercon), +}; + +static struct snd_soc_codec_driver soc_codec_dev_ak4648 = { + .probe = ak4642_probe, + .remove = ak4642_remove, + .resume = ak4642_resume, + .set_bias_level = ak4642_set_bias_level, + .reg_cache_default = ak4648_reg, /* ak4648 reg */ + .reg_cache_size = ARRAY_SIZE(ak4648_reg), /* ak4648 reg */ .reg_word_size = sizeof(u8), - .reg_cache_default = ak4642_reg, .dapm_widgets = ak4642_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(ak4642_dapm_widgets), .dapm_routes = ak4642_intercon, @@ -512,7 +538,8 @@ static __devinit int ak4642_i2c_probe(struct i2c_client *i2c, ak4642->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c->dev, - &soc_codec_dev_ak4642, &ak4642_dai, 1); + (struct snd_soc_codec_driver *)id->driver_data, + &ak4642_dai, 1); if (ret < 0) kfree(ak4642); return ret; @@ -526,8 +553,9 @@ static __devexit int ak4642_i2c_remove(struct i2c_client *client) }
static const struct i2c_device_id ak4642_i2c_id[] = { - { "ak4642", 0 }, - { "ak4643", 0 }, + { "ak4642", (kernel_ulong_t)&soc_codec_dev_ak4642 }, + { "ak4643", (kernel_ulong_t)&soc_codec_dev_ak4642 }, + { "ak4648", (kernel_ulong_t)&soc_codec_dev_ak4648 }, { } }; MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);
participants (3)
-
Kuninori Morimoto
-
kuninori.morimoto.gx@renesas.com
-
Mark Brown