2013-05-30 14:13:29

by Ondrej Zary

[permalink] [raw]
Subject: [PATCH] [resend] snd-es1968: Add radio support for MediaForte M56VAP

Add support for TEA5757 tuner on MediaForte M56VAP sound+modem+radio card.
The GPIO connection type is automatically detected (like snd-fm801 driver).

Also add a safety subsystem vendor check to skip radio detection if vendor
differs from ESS (so we don't touch GPIOs on laptops).

Tested with SF64-PCE2 and M56VAP cards.

Signed-off-by: Ondrej Zary <[email protected]>
---
sound/pci/es1968.c | 73 +++++++++++++++++++++++++++++++++++----------------
1 files changed, 50 insertions(+), 23 deletions(-)

diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index a1f32b5..db08641 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -564,6 +564,7 @@ struct es1968 {
#ifdef CONFIG_SND_ES1968_RADIO
struct v4l2_device v4l2_dev;
struct snd_tea575x tea;
+ unsigned int tea575x_tuner;
#endif
};

@@ -2557,37 +2558,47 @@ static int snd_es1968_input_register(struct es1968 *chip)
bits 1=unmask write to given bit */
#define IO_DIR 8 /* direction register offset from GPIO_DATA
bits 0/1=read/write direction */
-/* mask bits for GPIO lines */
-#define STR_DATA 0x0040 /* GPIO6 */
-#define STR_CLK 0x0080 /* GPIO7 */
-#define STR_WREN 0x0100 /* GPIO8 */
-#define STR_MOST 0x0200 /* GPIO9 */
+
+/* GPIO to TEA575x maps */
+struct snd_es1968_tea575x_gpio {
+ u8 data, clk, wren, most;
+ char *name;
+};
+
+static struct snd_es1968_tea575x_gpio snd_es1968_tea575x_gpios[] = {
+ { .data = 6, .clk = 7, .wren = 8, .most = 9, .name = "SF64-PCE2" },
+ { .data = 7, .clk = 8, .wren = 6, .most = 10, .name = "M56VAP" },
+};
+
+#define get_tea575x_gpio(chip) \
+ (&snd_es1968_tea575x_gpios[(chip)->tea575x_tuner])
+

static void snd_es1968_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
{
struct es1968 *chip = tea->private_data;
- unsigned long io = chip->io_port + GPIO_DATA;
+ struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip);
u16 val = 0;

- val |= (pins & TEA575X_DATA) ? STR_DATA : 0;
- val |= (pins & TEA575X_CLK) ? STR_CLK : 0;
- val |= (pins & TEA575X_WREN) ? STR_WREN : 0;
+ val |= (pins & TEA575X_DATA) ? (1 << gpio.data) : 0;
+ val |= (pins & TEA575X_CLK) ? (1 << gpio.clk) : 0;
+ val |= (pins & TEA575X_WREN) ? (1 << gpio.wren) : 0;

- outw(val, io);
+ outw(val, chip->io_port + GPIO_DATA);
}

static u8 snd_es1968_tea575x_get_pins(struct snd_tea575x *tea)
{
struct es1968 *chip = tea->private_data;
- unsigned long io = chip->io_port + GPIO_DATA;
- u16 val = inw(io);
- u8 ret;
+ struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip);
+ u16 val = inw(chip->io_port + GPIO_DATA);
+ u8 ret = 0;

- ret = 0;
- if (val & STR_DATA)
+ if (val & (1 << gpio.data))
ret |= TEA575X_DATA;
- if (val & STR_MOST)
+ if (val & (1 << gpio.most))
ret |= TEA575X_MOST;
+
return ret;
}

@@ -2596,13 +2607,18 @@ static void snd_es1968_tea575x_set_direction(struct snd_tea575x *tea, bool outpu
struct es1968 *chip = tea->private_data;
unsigned long io = chip->io_port + GPIO_DATA;
u16 odir = inw(io + IO_DIR);
+ struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip);

if (output) {
- outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK);
- outw(odir | STR_DATA | STR_CLK | STR_WREN, io + IO_DIR);
+ outw(~((1 << gpio.data) | (1 << gpio.clk) | (1 << gpio.wren)),
+ io + IO_MASK);
+ outw(odir | (1 << gpio.data) | (1 << gpio.clk) | (1 << gpio.wren),
+ io + IO_DIR);
} else {
- outw(~(STR_CLK | STR_WREN | STR_DATA | STR_MOST), io + IO_MASK);
- outw((odir & ~(STR_DATA | STR_MOST)) | STR_CLK | STR_WREN, io + IO_DIR);
+ outw(~((1 << gpio.clk) | (1 << gpio.wren) | (1 << gpio.data) | (1 << gpio.most)),
+ io + IO_MASK);
+ outw((odir & ~((1 << gpio.data) | (1 << gpio.most)))
+ | (1 << gpio.clk) | (1 << gpio.wren), io + IO_DIR);
}
}

@@ -2772,6 +2788,9 @@ static int snd_es1968_create(struct snd_card *card,
snd_card_set_dev(card, &pci->dev);

#ifdef CONFIG_SND_ES1968_RADIO
+ /* don't play with GPIOs on laptops */
+ if (chip->pci->subsystem_vendor != 0x125d)
+ goto no_radio;
err = v4l2_device_register(&pci->dev, &chip->v4l2_dev);
if (err < 0) {
snd_es1968_free(chip);
@@ -2781,10 +2800,18 @@ static int snd_es1968_create(struct snd_card *card,
chip->tea.private_data = chip;
chip->tea.radio_nr = radio_nr;
chip->tea.ops = &snd_es1968_tea_ops;
- strlcpy(chip->tea.card, "SF64-PCE2", sizeof(chip->tea.card));
sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
- if (!snd_tea575x_init(&chip->tea, THIS_MODULE))
- printk(KERN_INFO "es1968: detected TEA575x radio\n");
+ for (i = 0; i < ARRAY_SIZE(snd_es1968_tea575x_gpios); i++) {
+ chip->tea575x_tuner = i;
+ if (!snd_tea575x_init(&chip->tea, THIS_MODULE)) {
+ snd_printk(KERN_INFO "es1968: detected TEA575x radio type %s\n",
+ get_tea575x_gpio(chip)->name);
+ strlcpy(chip->tea.card, get_tea575x_gpio(chip)->name,
+ sizeof(chip->tea.card));
+ break;
+ }
+ }
+no_radio:
#endif

*chip_ret = chip;
--
Ondrej Zary


2013-05-31 06:42:08

by Takashi Iwai

[permalink] [raw]
Subject: Re: [alsa-devel] [PATCH] [resend] snd-es1968: Add radio support for MediaForte M56VAP

At Thu, 30 May 2013 16:13:09 +0200,
Ondrej Zary wrote:
>
> Add support for TEA5757 tuner on MediaForte M56VAP sound+modem+radio card.
> The GPIO connection type is automatically detected (like snd-fm801 driver).
>
> Also add a safety subsystem vendor check to skip radio detection if vendor
> differs from ESS (so we don't touch GPIOs on laptops).
>
> Tested with SF64-PCE2 and M56VAP cards.
>
> Signed-off-by: Ondrej Zary <[email protected]>

Thanks, applied.

At the next time, please add maintainers to Cc.


Takashi

> ---
> sound/pci/es1968.c | 73 +++++++++++++++++++++++++++++++++++----------------
> 1 files changed, 50 insertions(+), 23 deletions(-)
>
> diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
> index a1f32b5..db08641 100644
> --- a/sound/pci/es1968.c
> +++ b/sound/pci/es1968.c
> @@ -564,6 +564,7 @@ struct es1968 {
> #ifdef CONFIG_SND_ES1968_RADIO
> struct v4l2_device v4l2_dev;
> struct snd_tea575x tea;
> + unsigned int tea575x_tuner;
> #endif
> };
>
> @@ -2557,37 +2558,47 @@ static int snd_es1968_input_register(struct es1968 *chip)
> bits 1=unmask write to given bit */
> #define IO_DIR 8 /* direction register offset from GPIO_DATA
> bits 0/1=read/write direction */
> -/* mask bits for GPIO lines */
> -#define STR_DATA 0x0040 /* GPIO6 */
> -#define STR_CLK 0x0080 /* GPIO7 */
> -#define STR_WREN 0x0100 /* GPIO8 */
> -#define STR_MOST 0x0200 /* GPIO9 */
> +
> +/* GPIO to TEA575x maps */
> +struct snd_es1968_tea575x_gpio {
> + u8 data, clk, wren, most;
> + char *name;
> +};
> +
> +static struct snd_es1968_tea575x_gpio snd_es1968_tea575x_gpios[] = {
> + { .data = 6, .clk = 7, .wren = 8, .most = 9, .name = "SF64-PCE2" },
> + { .data = 7, .clk = 8, .wren = 6, .most = 10, .name = "M56VAP" },
> +};
> +
> +#define get_tea575x_gpio(chip) \
> + (&snd_es1968_tea575x_gpios[(chip)->tea575x_tuner])
> +
>
> static void snd_es1968_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
> {
> struct es1968 *chip = tea->private_data;
> - unsigned long io = chip->io_port + GPIO_DATA;
> + struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip);
> u16 val = 0;
>
> - val |= (pins & TEA575X_DATA) ? STR_DATA : 0;
> - val |= (pins & TEA575X_CLK) ? STR_CLK : 0;
> - val |= (pins & TEA575X_WREN) ? STR_WREN : 0;
> + val |= (pins & TEA575X_DATA) ? (1 << gpio.data) : 0;
> + val |= (pins & TEA575X_CLK) ? (1 << gpio.clk) : 0;
> + val |= (pins & TEA575X_WREN) ? (1 << gpio.wren) : 0;
>
> - outw(val, io);
> + outw(val, chip->io_port + GPIO_DATA);
> }
>
> static u8 snd_es1968_tea575x_get_pins(struct snd_tea575x *tea)
> {
> struct es1968 *chip = tea->private_data;
> - unsigned long io = chip->io_port + GPIO_DATA;
> - u16 val = inw(io);
> - u8 ret;
> + struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip);
> + u16 val = inw(chip->io_port + GPIO_DATA);
> + u8 ret = 0;
>
> - ret = 0;
> - if (val & STR_DATA)
> + if (val & (1 << gpio.data))
> ret |= TEA575X_DATA;
> - if (val & STR_MOST)
> + if (val & (1 << gpio.most))
> ret |= TEA575X_MOST;
> +
> return ret;
> }
>
> @@ -2596,13 +2607,18 @@ static void snd_es1968_tea575x_set_direction(struct snd_tea575x *tea, bool outpu
> struct es1968 *chip = tea->private_data;
> unsigned long io = chip->io_port + GPIO_DATA;
> u16 odir = inw(io + IO_DIR);
> + struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip);
>
> if (output) {
> - outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK);
> - outw(odir | STR_DATA | STR_CLK | STR_WREN, io + IO_DIR);
> + outw(~((1 << gpio.data) | (1 << gpio.clk) | (1 << gpio.wren)),
> + io + IO_MASK);
> + outw(odir | (1 << gpio.data) | (1 << gpio.clk) | (1 << gpio.wren),
> + io + IO_DIR);
> } else {
> - outw(~(STR_CLK | STR_WREN | STR_DATA | STR_MOST), io + IO_MASK);
> - outw((odir & ~(STR_DATA | STR_MOST)) | STR_CLK | STR_WREN, io + IO_DIR);
> + outw(~((1 << gpio.clk) | (1 << gpio.wren) | (1 << gpio.data) | (1 << gpio.most)),
> + io + IO_MASK);
> + outw((odir & ~((1 << gpio.data) | (1 << gpio.most)))
> + | (1 << gpio.clk) | (1 << gpio.wren), io + IO_DIR);
> }
> }
>
> @@ -2772,6 +2788,9 @@ static int snd_es1968_create(struct snd_card *card,
> snd_card_set_dev(card, &pci->dev);
>
> #ifdef CONFIG_SND_ES1968_RADIO
> + /* don't play with GPIOs on laptops */
> + if (chip->pci->subsystem_vendor != 0x125d)
> + goto no_radio;
> err = v4l2_device_register(&pci->dev, &chip->v4l2_dev);
> if (err < 0) {
> snd_es1968_free(chip);
> @@ -2781,10 +2800,18 @@ static int snd_es1968_create(struct snd_card *card,
> chip->tea.private_data = chip;
> chip->tea.radio_nr = radio_nr;
> chip->tea.ops = &snd_es1968_tea_ops;
> - strlcpy(chip->tea.card, "SF64-PCE2", sizeof(chip->tea.card));
> sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
> - if (!snd_tea575x_init(&chip->tea, THIS_MODULE))
> - printk(KERN_INFO "es1968: detected TEA575x radio\n");
> + for (i = 0; i < ARRAY_SIZE(snd_es1968_tea575x_gpios); i++) {
> + chip->tea575x_tuner = i;
> + if (!snd_tea575x_init(&chip->tea, THIS_MODULE)) {
> + snd_printk(KERN_INFO "es1968: detected TEA575x radio type %s\n",
> + get_tea575x_gpio(chip)->name);
> + strlcpy(chip->tea.card, get_tea575x_gpio(chip)->name,
> + sizeof(chip->tea.card));
> + break;
> + }
> + }
> +no_radio:
> #endif
>
> *chip_ret = chip;
> --
> Ondrej Zary
> _______________________________________________
> Alsa-devel mailing list
> [email protected]
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>