Re: [PATCH v4 2/5] MFD: WL1273 FM Radio: MFD driver for the FM radio.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




--- On Thu, 19/8/10, Matti J. Aaltonen <matti.j.aaltonen@xxxxxxxxx> wrote:

> From: Matti J. Aaltonen <matti.j.aaltonen@xxxxxxxxx>
> Subject: Re: [PATCH v4 2/5] MFD: WL1273 FM Radio: MFD driver for the FM radio.
> To: "ext Pavan Savoy" <pavan_savoy@xxxxxxxxxxx>
> Cc: "Mauro Carvalho Chehab" <mchehab@xxxxxxxxxx>, "linux-media@xxxxxxxxxxxxxxx" <linux-media@xxxxxxxxxxxxxxx>, "hverkuil@xxxxxxxxx" <hverkuil@xxxxxxxxx>, "Valentin Eduardo (Nokia-MS/Helsinki)" <eduardo.valentin@xxxxxxxxx>
> Date: Thursday, 19 August, 2010, 12:35 PM
> Hello.
> 
> 
> On Wed, 2010-08-18 at 20:14 +0200, ext Pavan Savoy wrote:
> > --- On Wed, 7/7/10, Pavan Savoy <pavan_savoy@xxxxxx>
> wrote:
> > > 
> > > From: Pavan Savoy <pavan_savoy@xxxxxx>
> > > Subject: Re: [PATCH v4 2/5] MFD: WL1273 FM Radio:
> MFD driver for the FM radio.
> > > To: "Matti J. Aaltonen" <matti.j.aaltonen@xxxxxxxxx>,
> "Mauro Carvalho Chehab" <mchehab@xxxxxxxxxx>
> > > Cc: linux-media@xxxxxxxxxxxxxxx,
> hverkuil@xxxxxxxxx,
> eduardo.valentin@xxxxxxxxx,
> "pavan savoy" <pavan_savoy@xxxxxxxxxxx>
> > > Date: Wednesday, 7 July, 2010, 10:51 AM
> > >
> > > --- On Tue, 6/7/10, Mauro Carvalho Chehab <mchehab@xxxxxxxxxx>
> > > wrote:
> > >
> > > > From: Mauro Carvalho Chehab <mchehab@xxxxxxxxxx>
> > > > Subject: Re: [PATCH v4 2/5] MFD: WL1273 FM
> Radio: MFD
> > > driver for the FM radio.
> > > > To: "Matti J. Aaltonen" <matti.j.aaltonen@xxxxxxxxx>
> > > > Cc: linux-media@xxxxxxxxxxxxxxx,
> > > hverkuil@xxxxxxxxx,
> > > eduardo.valentin@xxxxxxxxx
> > > > Date: Tuesday, 6 July, 2010, 8:04 AM
> > > > Em 04-06-2010 07:34, Matti J.
> > > > Aaltonen escreveu:
> > > > > This is a parent driver for two child
> drivers:
> > > the
> > > > V4L2 driver and
> > > > > the ALSA codec driver. The MFD part
> provides the
> > > I2C
> > > > communication
> > > > > to the device and a couple of functions
> that are
> > > > called from both
> > > > > children.
> > >
> > > Where can I have a look at the whole code ? As in
> some
> > > local tree, where all codes are put up ?
> > > Basically, we have a V4L2 driver for WL128x
> (using TTY as
> > > transport) and plan to push them soon ...
> > >
> > > This would be a nice input ...
> > 
> > Anywhere I can have a look at the whole code?
> > We are trying to push out V4L2 drivers for FM on 128x,
> and intend to use several V4L2 new ioctls which you have
> defined (_BAND_) being one of them.
> > 
> > Also we plan to push FM Tx of it too.. TX_CLASS from
> V4L2 has most of the ioctls and plan to introduce the rest.
> 
> I'm sorry for not answering to you earlier. But I don't
> have my own
> public repository. But to create the whole thing is
> extremely simple:
> just take the current mainline tree and apply my patches on
> top of it...

Yep, that I can do, the reason I asked for was, we've pushed a few patches of our own for WL1283 over shared transport/UART (Not HCI-VS, but I2C like commands, packed in a CH8 protocol format).
The FM register set in both chip are a match, with only transport being the difference (i2c vs. UART).
Also we have the Tx version of driver ready too, it just needs a bit of cleanup and more conformance to already existing V4L2 TX Class..

So I was wondering, although there is no problem with WL1273 with I2C and WL1283 with UART being there on the kernel (whenever that happens), but it would be way more cooler if the transport was say abstracted out ..

what do you say? just an idea...

> Best Regards,
> Matti
> 
> > 
> > >
> > > > > Signed-off-by: Matti J. Aaltonen <matti.j.aaltonen@xxxxxxxxx>
> > > > > ---
> > > > >  drivers/mfd/Kconfig
> > > >      |    6 +
> > > > >  drivers/mfd/Makefile
> > > >     |    2 +
> > > > >  drivers/mfd/wl1273-core.c
> > > >    |  616
> > > > +++++++++++++++++++++++++++++++++++++++
> > > > >  include/linux/mfd/wl1273-core.h
> |  326
> > > > +++++++++++++++++++++
> > > > >  4 files changed, 950
> insertions(+), 0
> > > > deletions(-)
> > > > >  create mode 100644
> drivers/mfd/wl1273-core.c
> > > > >  create mode 100644
> > > > include/linux/mfd/wl1273-core.h
> > > > >
> > > > > diff --git a/drivers/mfd/Kconfig
> > > > b/drivers/mfd/Kconfig
> > > > > index 413576a..5998a94 100644
> > > > > --- a/drivers/mfd/Kconfig
> > > > > +++ b/drivers/mfd/Kconfig
> > > > > @@ -135,6 +135,12 @@ config
> TWL4030_CODEC
> > > > >      select MFD_CORE
> > > > >      default n
> > > > >
> > > > > +config WL1273_CORE
> > > > > +    bool
> > > > > +    depends on I2C
> > > > > +    select MFD_CORE
> > > > > +    default n
> > > > > +
> > > > >  config MFD_TMIO
> > > > >      bool
> > > > >      default n
> > > > > diff --git a/drivers/mfd/Makefile
> > > > b/drivers/mfd/Makefile
> > > > > index 78295d6..46e611d 100644
> > > > > --- a/drivers/mfd/Makefile
> > > > > +++ b/drivers/mfd/Makefile
> > > > > @@ -30,6 +30,8 @@
> > > > obj-$(CONFIG_TWL4030_CORE)    +=
> twl-core.o
> > > > twl4030-irq.o twl6030-irq.o
> > > > >  obj-$(CONFIG_TWL4030_POWER) 
>   +=
> > > > twl4030-power.o
> > > > >  obj-$(CONFIG_TWL4030_CODEC) 
>   +=
> > > > twl4030-codec.o
> > > > >
> > > > > +obj-$(CONFIG_WL1273_CORE)   
> +=
> > > > wl1273-core.o
> > > > > +
> > > > >  obj-$(CONFIG_MFD_MC13783) 
>   +=
> > > > mc13783-core.o
> > > > >
> > > > >  obj-$(CONFIG_MFD_CORE)
> > > >     += mfd-core.o
> > > > > diff --git a/drivers/mfd/wl1273-core.c
> > > > b/drivers/mfd/wl1273-core.c
> > > > > new file mode 100644
> > > > > index 0000000..6c7dbba
> > > > > --- /dev/null
> > > > > +++ b/drivers/mfd/wl1273-core.c
> > > > > @@ -0,0 +1,616 @@
> > > > > +/*
> > > > > + * MFD driver for wl1273 FM radio and
> audio
> > > codec
> > > > submodules.
> > > > > + *
> > > > > + * Author:    Matti Aaltonen
> <matti.j.aaltonen@xxxxxxxxx>
> > > > > + *
> > > > > + * Copyright:   (C)
> 2010 Nokia
> > > > Corporation
> > > > > + *
> > > > > + * This program is free software; you
> can
> > > > redistribute it and/or modify
> > > > > + * it under the terms of the GNU
> General Public
> > > > License version 2 as
> > > > > + * published by the Free Software
> Foundation.
> > > > > + *
> > > > > + * This program is distributed in the
> hope that
> > > it
> > > > will be useful, but
> > > > > + * WITHOUT ANY WARRANTY; without even
> the
> > > implied
> > > > warranty of
> > > > > + * MERCHANTABILITY or FITNESS FOR A
> PARTICULAR
> > > > PURPOSE.  See the GNU
> > > > > + * General Public License for more
> details.
> > > > > + *
> > > > > + * You should have received a copy of
> the GNU
> > > General
> > > > Public License
> > > > > + * along with this program; if not,
> write to the
> > > Free
> > > > Software
> > > > > + * Foundation, Inc., 51 Franklin St,
> Fifth
> > > Floor,
> > > > Boston, MA
> > > > > + * 02110-1301 USA
> > > > > + *
> > > > > + */
> > > > > +
> > > > > +#undef DEBUG
> > > > > +
> > > > > +#include <asm/unaligned.h>
> > > > > +#include <linux/completion.h>
> > > > > +#include <linux/delay.h>
> > > > > +#include <linux/i2c.h>
> > > > > +#include <linux/interrupt.h>
> > > > > +#include <linux/module.h>
> > > > > +#include <linux/types.h>
> > > > > +#include <linux/kernel.h>
> > > > > +#include <linux/fs.h>
> > > > > +#include
> <linux/platform_device.h>
> > > > > +#include <linux/mfd/core.h>
> > > > > +#include
> <linux/mfd/wl1273-core.h>
> > > > > +#include <media/v4l2-common.h>
> > > > > +
> > > > > +#define DRIVER_DESC "WL1273 FM Radio
> Core"
> > > > > +
> > > > > +#define
> > > > WL1273_IRQ_MASK 
>    (WL1273_FR_EVENT
> > > >     |    \
> > > > > +
> > > >   
>    WL1273_POW_ENB_EVENT)
> > > > > +
> > > > > +static const struct band_info bands[]
> = {
> > > > > +    /* USA & Europe */
> > > > > +    {
> > > > > +
> > > > .bottom_frequency    = 87500,
> > > > > +
> > > > .top_frequency        =
> > > > 108000,
> > > > > +
> > > > .band
> > > >     =
> V4L2_FM_BAND_OTHER,
> > > > > +    },
> > > > > +    /* Japan */
> > > > > +    {
> > > > > +
> > > > .bottom_frequency    = 76000,
> > > > > +
> > > > .top_frequency        =
> > > > 90000,
> > > > > +
> > > > .band
> > > >     =
> V4L2_FM_BAND_JAPAN,
> > > > > +    },
> > > > > +};
> > > > > +
> > > > > +/*
> > > > > + * static unsigned char radio_band -
> Band
> > > > > + *
> > > > > + * The bands are 0=Japan,
> 1=USA-Europe.
> > > USA-Europe is
> > > > the default.
> > > > > + */
> > > > > +static unsigned char radio_band = 1;
> > > > > +module_param(radio_band, byte, 0);
> > > > > +MODULE_PARM_DESC(radio_band, "Band:
> 0=Japan,
> > > > 1=USA-Europe*");
> > > > > +
> > > > > +/*
> > > > > + * static unsigned int rds_buf - the
> number of
> > > RDS
> > > > buffer blocks used.
> > > > > + *
> > > > > + * The default number is 100.
> > > > > + */
> > > > > +static unsigned int rds_buf = 100;
> > > > > +module_param(rds_buf, uint, 0);
> > > > > +MODULE_PARM_DESC(rds_buf, "RDS buffer
> entries:
> > > > *100*");
> > > > > +
> > > > > +int wl1273_fm_read_reg(struct
> wl1273_core *core,
> > > u8
> > > > reg, u16 *value)
> > > > > +{
> > > > > +    struct i2c_client
> *client =
> > > > core->i2c_dev;
> > > > > +    u8 b[2];
> > > > > +    int r;
> > > > > +
> > > > > +    r =
> > > > i2c_smbus_read_i2c_block_data(client, reg,
> 2, b);
> > > > > +    if (r != 2) {
> > > > > +
> > > > dev_err(&client->dev, "%s: Read: %d
> fails.\n",
> > > > __func__, reg);
> > > > > +        return
> > > > -EREMOTEIO;
> > > > > +    }
> > > > > +
> > > > > +    *value = (u16)b[0]
> << 8 |
> > > > b[1];
> > > > > +
> > > > > +    return 0;
> > > > > +}
> > > > > +EXPORT_SYMBOL(wl1273_fm_read_reg);
> > > > > +
> > > > > +int wl1273_fm_write_cmd(struct
> wl1273_core
> > > *core, u8
> > > > cmd, u16 param)
> > > > > +{
> > > > > +    struct i2c_client
> *client =
> > > > core->i2c_dev;
> > > > > +    u8 buf[] = { (param
> >> 8)
> > > > & 0xff, param & 0xff };
> > > > > +    int r;
> > > > > +
> > > > > +    r =
> > > > i2c_smbus_write_i2c_block_data(client, cmd,
> 2, buf);
> > > > > +    if (r) {
> > > > > +
> > > > dev_err(&client->dev, "%s: Cmd: %d
> fails.\n",
> > > > __func__, cmd);
> > > > > +        return r;
> > > > > +    }
> > > > > +
> > > > > +    return 0;
> > > > > +}
> > > > > +EXPORT_SYMBOL(wl1273_fm_write_cmd);
> > > > > +
> > > > > +int wl1273_fm_write_data(struct
> wl1273_core
> > > *core, u8
> > > > *data, u16 len)
> > > > > +{
> > > > > +    struct i2c_client
> *client =
> > > > core->i2c_dev;
> > > > > +    struct i2c_msg msg[1];
> > > > > +    int r;
> > > > > +
> > > > > +    msg[0].addr =
> client->addr;
> > > > > +    msg[0].flags = 0;
> > > > > +    msg[0].buf = data;
> > > > > +    msg[0].len = len;
> > > > > +
> > > > > +    r =
> > > > i2c_transfer(client->adapter, msg, 1);
> > > > > +
> > > > > +    if (r != 1) {
> > > > > +
> > > > dev_err(&client->dev, "%s: write
> error.\n",
> > > > __func__);
> > > > > +        return
> > > > -EREMOTEIO;
> > > > > +    }
> > > > > +
> > > > > +    return 0;
> > > > > +}
> > > > > +EXPORT_SYMBOL(wl1273_fm_write_data);
> > > > > +
> > > > > +/**
> > > > > + * wl1273_fm_set_audio() - 
>   Set
> > > > audio mode.
> > > > > + * @core:
> > > >     A pointer to the
> device struct.
> > > > > + * @new_mode:
> > > >     The new audio mode.
> > > > > + *
> > > > > + * Audio modes are
> WL1273_AUDIO_DIGITAL and
> > > > WL1273_AUDIO_ANALOG.
> > > > > + */
> > > > > +int wl1273_fm_set_audio(struct
> wl1273_core
> > > *core,
> > > > unsigned int new_mode)
> > > > > +{
> > > > > +    int r = 0;
> > > > > +
> > > > > +    if (core->mode ==
> > > > WL1273_MODE_OFF ||
> > > > > +       
> core->mode ==
> > > > WL1273_MODE_SUSPENDED)
> > > > > +        return
> -EPERM;
> > > > > +
> > > > > +    if (core->mode ==
> > > > WL1273_MODE_RX && new_mode ==
> > > WL1273_AUDIO_DIGITAL)
> > > > {
> > > > > +        r =
> > > > wl1273_fm_write_cmd(core,
> WL1273_PCM_MODE_SET,
> > > > > +
> > > >
> > > > WL1273_PCM_DEF_MODE);
> > > > > +        if (r)
> > > > > +
> > > >     goto out;
> > > > > +
> > > > > +        r =
> > > > wl1273_fm_write_cmd(core,
> WL1273_I2S_MODE_CONFIG_SET,
> > > > > +
> > > >
> > > > core->i2s_mode);
> > > > > +        if (r)
> > > > > +
> > > >     goto out;
> > > > > +
> > > > > +        r =
> > > > wl1273_fm_write_cmd(core,
> WL1273_AUDIO_ENABLE,
> > > > > +
> > > >
> > > > WL1273_AUDIO_ENABLE_I2S);
> > > > > +        if (r)
> > > > > +
> > > >     goto out;
> > > > > +
> > > > > +    } else if (core->mode
> ==
> > > > WL1273_MODE_RX &&
> > > > > +
> > > >    new_mode ==
> WL1273_AUDIO_ANALOG) {
> > > > > +        r =
> > > > wl1273_fm_write_cmd(core,
> WL1273_AUDIO_ENABLE,
> > > > > +
> > > >
> > > > WL1273_AUDIO_ENABLE_ANALOG);
> > > > > +        if (r)
> > > > > +
> > > >     goto out;
> > > > > +
> > > > > +    } else if (core->mode
> ==
> > > > WL1273_MODE_TX &&
> > > > > +
> > > >    new_mode ==
> WL1273_AUDIO_DIGITAL) {
> > > > > +        r =
> > > > wl1273_fm_write_cmd(core,
> WL1273_I2S_MODE_CONFIG_SET,
> > > > > +
> > > >
> > > > core->i2s_mode);
> > > > > +        if (r)
> > > > > +
> > > >     goto out;
> > > > > +
> > > > > +        r =
> > > > wl1273_fm_write_cmd(core,
> WL1273_AUDIO_IO_SET,
> > > > > +
> > > >
> > > > WL1273_AUDIO_IO_SET_I2S);
> > > > > +        if (r)
> > > > > +
> > > >     goto out;
> > > > > +
> > > > > +    } else if (core->mode
> ==
> > > > WL1273_MODE_TX &&
> > > > > +
> > > >    new_mode ==
> WL1273_AUDIO_ANALOG) {
> > > > > +        r =
> > > > wl1273_fm_write_cmd(core,
> WL1273_AUDIO_IO_SET,
> > > > > +
> > > >
> > > > WL1273_AUDIO_IO_SET_ANALOG);
> > > > > +        if (r)
> > > > > +
> > > >     goto out;
> > > > > +    }
> > > > > +
> > > > > +    core->audio_mode =
> new_mode;
> > > > > +
> > > > > +out:
> > > > > +    return r;
> > > > > +}
> > > > > +EXPORT_SYMBOL(wl1273_fm_set_audio);
> > > > > +
> > > > > +/**
> > > > > + * wl1273_fm_set_volume() - 
>   Set
> > > > volume.
> > > > > + * @core:
> > > >     A pointer to the
> device struct.
> > > > > + * @volume:
> > > >     The new volume
> value.
> > > > > + */
> > > > > +int wl1273_fm_set_volume(struct
> wl1273_core
> > > *core,
> > > > unsigned int volume)
> > > > > +{
> > > > > +    u16 val;
> > > > > +    int r;
> > > > > +
> > > > > +    if (volume >
> > > > WL1273_MAX_VOLUME)
> > > > > +        return
> > > > -EINVAL;
> > > > > +
> > > > > +    if (core->volume ==
> volume)
> > > > > +        return 0;
> > > > > +
> > > > > +    val = volume;
> > > > > +    r =
> wl1273_fm_read_reg(core,
> > > > WL1273_VOLUME_SET, &val);
> > > > > +    if (r)
> > > > > +        return r;
> > > > > +
> > > > > +    core->volume =
> volume;
> > > > > +    return 0;
> > > > > +}
> > > > > +EXPORT_SYMBOL(wl1273_fm_set_volume);
> > > > > +
> > > > > +#define
> > > > WL1273_RDS_FIFO_EMPTY(status)   
> (!(1
> > > > << 6 &  status))
> > > > > +
> > > > > +#define
> > > > WL1273_RDS_CORRECTABLE_ERROR    (1
> <<
> > > > 3)
> > > > > +#define
> > > > WL1273_RDS_UNCORRECTABLE_ERROR   
> (1 <<
> > > > 4)
> > > > > +
> > > > > +static int wl1273_fm_rds(struct
> wl1273_core
> > > *core)
> > > > > +{
> > > > > +    struct i2c_client
> *client =
> > > > core->i2c_dev;
> > > > > +    struct device *dev =
> > > > &client->dev;
> > > > > +    struct v4l2_rds_data rds
> = { 0, 0,
> > > > 0 };
> > > > > +    struct i2c_msg msg[] =
> {
> > > > > +        {
> > > > > +
> > > >     .addr =
> client->addr,
> > > > > +
> > > >     .flags = 0,
> > > > > +
> > > >     .buf = b0,
> > > > > +
> > > >     .len = 1
> > > > > +        },
> > > > > +        {
> > > > > +
> > > >     .addr =
> client->addr,
> > > > > +
> > > >     .flags = I2C_M_RD,
> > > > > +
> > > >     .buf = (u8 *)
> &rds,
> > > > > +
> > > >     .len = 3
> > > > > +        }
> > > > > +    };
> > > > > +    u8 b0[] = {
> WL1273_RDS_DATA_GET },
> > > > status;
> > > > > +    u16 val;
> > > > > +    int r;
> > > > > +
> > > > > +    r =
> wl1273_fm_read_reg(core,
> > > > WL1273_RDS_SYNC_GET, &val);
> > > > > +    if (r)
> > > > > +        return r;
> > > > > +
> > > > > +    /* Is RDS decoder
> synchronized?
> > > > */
> > > > > +    if ((val & 0x01) ==
> 0)
> > > > > +        return
> > > > -EAGAIN;
> > > > > +
> > > > > +    /* copy all four RDS
> blocks to
> > > > internal buffer */
> > > > > +    do {
> > > > > +        r =
> > > > i2c_transfer(client->adapter, msg, 2);
> > > > > +        if (r !=
> 2) {
> > > > > +
> > > >     dev_err(dev,
> WL1273_FM_DRIVER_NAME
> > > > > +
> > > >         ": %s:
> read_rds error
> > > > r == %i)\n",
> > > > > +
> > > >     
>    __func__, r);
> > > > > +        }
> > > > > +
> > > > > +        status =
> > > > rds.block;
> > > > > +
> > > > > +        if
> > > > (WL1273_RDS_FIFO_EMPTY(status))
> > > > > +
> > > >     break;
> > > > > +
> > > > > +        /* copy
> RDS
> > > > block to internal buffer */
> > > > > +
> > > >
> memcpy(&core->buffer[core->wr_index],
> > > &rds,
> > > > 3);
> > > > > +
> > > > core->wr_index += 3;
> > > > > +
> > > > > +        /* copy
> the
> > > > error bits to standard positions */
> > > > > +        if
> > > > (WL1273_RDS_UNCORRECTABLE_ERROR &
> status) {
> > > > > +
> > > >     rds.block |=
> V4L2_RDS_BLOCK_ERROR;
> > > > > +
> > > >     rds.block &=
> > > > ~V4L2_RDS_BLOCK_CORRECTED;
> > > > > +        } else if
> > > > (WL1273_RDS_CORRECTABLE_ERROR & status)
> {
> > > > > +
> > > >     rds.block &=
> ~V4L2_RDS_BLOCK_ERROR;
> > > > > +
> > > >     rds.block |=
> V4L2_RDS_BLOCK_CORRECTED;
> > > > > +        } else {
> > > > > +
> > > >     rds.block &=
> ~V4L2_RDS_BLOCK_ERROR;
> > > > > +
> > > >     rds.block &=
> > > > ~V4L2_RDS_BLOCK_CORRECTED;
> > > > > +        }
> > > > > +
> > > > > +        /* wrap
> write
> > > > pointer */
> > > > > +        if
> > > > (core->wr_index >= core->buf_size)
> > > > > +
> > > >     core->wr_index =
> 0;
> > > > > +
> > > > > +        /* check
> for
> > > > overflow & start over */
> > > > > +        if
> > > > (core->wr_index == core->rd_index) {
> > > > > +
> > > >     dev_dbg(dev, "RDS
> OVERFLOW");
> > > > > +
> > > > > +
> > > >     core->rd_index =
> 0;
> > > > > +
> > > >     core->wr_index =
> 0;
> > > > > +
> > > >     break;
> > > > > +        }
> > > > > +    } while
> > > > (!WL1273_RDS_FIFO_EMPTY(status));
> > > > > +
> > > > > +    /* wake up read queue
> */
> > > > > +    if (core->wr_index
> !=
> > > > core->rd_index)
> > > > > +
> > > >
> wake_up_interruptible(&core->read_queue);
> > > > > +
> > > > > +    return 0;
> > > > > +}
> > > > > +
> > > > > +static void wl1273_fm_rds_work(struct
> > > wl1273_core
> > > > *core)
> > > > > +{
> > > > > +    wl1273_fm_rds(core);
> > > > > +}
> > > > > +
> > > > > +static irqreturn_t
> > > wl1273_fm_irq_thread_handler(int
> > > > irq, void *dev_id)
> > > > > +{
> > > > > +    int r;
> > > > > +    u16 flags;
> > > > > +    struct wl1273_core *core
> =
> > > > dev_id;
> > > > > +
> > > > > +    r =
> wl1273_fm_read_reg(core,
> > > > WL1273_FLAG_GET, &flags);
> > > > > +    if (r)
> > > > > +        goto out;
> > > > > +
> > > > > +    if (flags &
> WL1273_BL_EVENT)
> > > > {
> > > > > +
> > > > core->irq_received = flags;
> > > > > +
> > > > dev_dbg(&core->i2c_dev->dev, "IRQ:
> BL\n");
> > > > > +    }
> > > > > +
> > > > > +    if (flags &
> WL1273_RDS_EVENT)
> > > > {
> > > > > +       
> msleep(200);
> > > > > +
> > > > > +
> > > > wl1273_fm_rds_work(core);
> > > > > +    }
> > > > > +
> > > > > +    if (flags &
> > > > WL1273_BBLK_EVENT)
> > > > > +
> > > > dev_dbg(&core->i2c_dev->dev,
> "IRQ:
> > > BBLK\n");
> > > > > +
> > > > > +    if (flags &
> > > > WL1273_LSYNC_EVENT)
> > > > > +
> > > > dev_dbg(&core->i2c_dev->dev,
> "IRQ:
> > > LSYNC\n");
> > > > > +
> > > > > +    if (flags &
> WL1273_LEV_EVENT)
> > > > {
> > > > > +        u16
> level;
> > > > > +
> > > > > +        r =
> > > > wl1273_fm_read_reg(core,
> WL1273_RSSI_LVL_GET,
> > > &level);
> > > > > +
> > > > > +        if (r)
> > > > > +
> > > >     goto out;
> > > > > +
> > > > > +        if (level
> >
> > > > 14)
> > > > > +
> > > > 
>    dev_dbg(&core->i2c_dev->dev,
> > > > "IRQ: LEV: 0x%x04\n",
> > > > > +
> > > >     
>    level);
> > > > > +    }
> > > > > +
> > > > > +    if (flags &
> > > > WL1273_IFFR_EVENT)
> > > > > +
> > > > dev_dbg(&core->i2c_dev->dev,
> "IRQ:
> > > IFFR\n");
> > > > > +
> > > > > +    if (flags &
> WL1273_PI_EVENT)
> > > > > +
> > > > dev_dbg(&core->i2c_dev->dev, "IRQ:
> PI\n");
> > > > > +
> > > > > +    if (flags &
> WL1273_PD_EVENT)
> > > > > +
> > > > dev_dbg(&core->i2c_dev->dev, "IRQ:
> PD\n");
> > > > > +
> > > > > +    if (flags &
> > > > WL1273_STIC_EVENT)
> > > > > +
> > > > dev_dbg(&core->i2c_dev->dev,
> "IRQ:
> > > STIC\n");
> > > > > +
> > > > > +    if (flags &
> WL1273_MAL_EVENT)
> > > > > +
> > > > dev_dbg(&core->i2c_dev->dev, "IRQ:
> MAL\n");
> > > > > +
> > > > > +    if (flags &
> > > > WL1273_POW_ENB_EVENT) {
> > > > > +
> > > > complete(&core->busy);
> > > > > +
> > > > dev_dbg(&core->i2c_dev->dev, "NOT
> BUSY\n");
> > > > > +
> > > > dev_dbg(&core->i2c_dev->dev,
> "IRQ:
> > > POW_ENB\n");
> > > > > +    }
> > > > > +
> > > > > +    if (flags &
> > > > WL1273_SCAN_OVER_EVENT)
> > > > > +
> > > > dev_dbg(&core->i2c_dev->dev,
> "IRQ:
> > > SCAN_OVER\n");
> > > > > +
> > > > > +    if (flags &
> > > > WL1273_ERROR_EVENT)
> > > > > +
> > > > dev_dbg(&core->i2c_dev->dev,
> "IRQ:
> > > ERROR\n");
> > > > > +
> > > > > +    if (flags &
> WL1273_FR_EVENT)
> > > > {
> > > > > +        u16 freq;
> > > > > +
> > > > > +
> > > > dev_dbg(&core->i2c_dev->dev, "IRQ:
> FR:\n");
> > > > > +
> > > > > +        if
> > > > (core->mode == WL1273_MODE_RX) {
> > > > > +
> > > >     r =
> wl1273_fm_write_cmd(core,
> > > > WL1273_TUNER_MODE_SET,
> > > > > +
> > > >
> > > > 
>    TUNER_MODE_STOP_SEARCH);
> > > > > +
> > > >     if (r) {
> > > > > +
> > > >
> > > > dev_err(&core->i2c_dev->dev,
> > > > > +
> > > >
> > > > "%s: TUNER_MODE_SET fails: %d\n",
> > > > > +
> > > >
> > > > __func__, r);
> > > > > +
> > > >         goto
> out;
> > > > > +
> > > >     }
> > > > > +
> > > > > +
> > > >     r =
> wl1273_fm_read_reg(core,
> > > > WL1273_FREQ_SET, &freq);
> > > > > +
> > > >     if (r)
> > > > > +
> > > >         goto
> out;
> > > > > +
> > > > > +
> > > > 
>    core->rx_frequency =
> > > > > +
> > > >
> > > > bands[core->band].bottom_frequency +
> > > > > +
> > > >         freq *
> 50;
> > > > > +
> > > > > +
> > > >     /*
> > > > > +
> > > >      *  The driver
> works
> > > > better with this msleep,
> > > > > +
> > > >      *  the
> documentation
> > > > doesn't mention it.
> > > > > +
> > > >      */
> > > > > +
> > > >     msleep(10);
> > > >
> > > >
> > > > msleep on an irq handler? You shouldn't be
> doing it!
> > > You're
> > > > not allowed to sleep
> > > > during IRQ time. Kernel can panic here.
> You'll
> > > probably
> > > > need to defer work and
> > > > handle it outside irq time.
> > > > > +
> > > > > +
> > > > 
>    dev_dbg(&core->i2c_dev->dev,
> > > > "%dkHz\n",
> > > > > +
> > > >
> > > > core->rx_frequency);
> > > > > +
> > > > > +        } else {
> > > > > +
> > > >     r =
> wl1273_fm_read_reg(core,
> > > > WL1273_CHANL_SET, &freq);
> > > > > +
> > > >     if (r)
> > > > > +
> > > >         goto
> out;
> > > > > +
> > > > > +
> > > > 
>    dev_dbg(&core->i2c_dev->dev,
> > > > "%dkHz\n", freq);
> > > > > +        }
> > > > > +
> > > > dev_dbg(&core->i2c_dev->dev, "%s:
> NOT
> > > BUSY\n",
> > > > __func__);
> > > > > +    }
> > > > > +
> > > > > +out:
> > > > > +   
> wl1273_fm_write_cmd(core,
> > > > WL1273_INT_MASK_SET,
> > > > > +
> > > >     
>    core->irq_flags);
> > > > > +   
> complete(&core->busy);
> > > > > +
> > > > > +    return IRQ_HANDLED;
> > > > > +}
> > > > > +
> > > > > +static struct i2c_device_id
> > > wl1273_driver_id_table[]
> > > > = {
> > > > > +    { WL1273_FM_DRIVER_NAME,
> 0 },
> > > > > +    { }
> > > > > +};
> > > > > +MODULE_DEVICE_TABLE(i2c,
> > > wl1273_driver_id_table);
> > > > > +
> > > > > +static int wl1273_core_remove(struct
> i2c_client
> > > > *client)
> > > > > +{
> > > > > +    struct wl1273_core *core
> =
> > > > i2c_get_clientdata(client);
> > > > > +    struct
> wl1273_fm_platform_data
> > > > *pdata =
> > > > > +
> > > > client->dev.platform_data;
> > > > > +
> > > > > +   
> dev_dbg(&client->dev,
> > > > "%s\n", __func__);
> > > > > +
> > > > > +
> > > > mfd_remove_devices(&client->dev);
> > > > > +   
> i2c_set_clientdata(client, core);
> > > > > +
> > > > > +    free_irq(client->irq,
> core);
> > > > > +   
> pdata->free_resources();
> > > > > +
> > > > > +    kfree(core->buffer);
> > > > > +    kfree(core);
> > > > > +
> > > > > +    return 0;
> > > > > +}
> > > > > +
> > > > > +static int __devinit
> wl1273_core_probe(struct
> > > > i2c_client *client,
> > > > > +
> > > >
> > > >    const struct i2c_device_id
> *id)
> > > > > +{
> > > > > +    struct
> wl1273_fm_platform_data
> > > > *pdata = client->dev.platform_data;
> > > > > +    int r = 0;
> > > > > +    struct wl1273_core
> *core;
> > > > > +    int children = 0;
> > > > > +
> > > > > +   
> dev_dbg(&client->dev,
> > > > "%s\n", __func__);
> > > > > +
> > > > > +    if (!pdata) {
> > > > > +
> > > > dev_err(&client->dev, "No platform
> data.\n");
> > > > > +        return
> > > > -EINVAL;
> > > > > +    }
> > > > > +
> > > > > +    core =
> kzalloc(sizeof(*core),
> > > > GFP_KERNEL);
> > > > > +    if (!core)
> > > > > +        return
> > > > -ENOMEM;
> > > > > +
> > > > > +    /* RDS buffer allocation
> */
> > > > > +    core->buf_size =
> rds_buf * 3;
> > > > > +    core->buffer =
> > > > kmalloc(core->buf_size, GFP_KERNEL);
> > > > > +    if (!core->buffer) {
> > > > > +
> > > > dev_err(&client->dev,
> > > > > +
> > > >     "Cannot allocate
> memory for RDS
> > > > buffer.\n");
> > > > > +        r =
> -ENOMEM;
> > > > > +        goto
> > > > err_kmalloc;
> > > > > +    }
> > > > > +
> > > > > +    core->irq_flags =
> > > > WL1273_IRQ_MASK;
> > > > > +    core->i2c_dev =
> client;
> > > > > +    core->rds_on =
> false;
> > > > > +    core->mode =
> WL1273_MODE_OFF;
> > > > > +    core->tx_power = 4;
> > > > > +    core->audio_mode =
> > > > WL1273_AUDIO_ANALOG;
> > > > > +    core->band =
> radio_band;
> > > > > +    core->bands = bands;
> > > > > +    core->number_of_bands
> =
> > > > ARRAY_SIZE(bands);
> > > > > +    core->i2s_mode =
> > > > WL1273_I2S_DEF_MODE;
> > > > > +    core->channel_number
> = 2;
> > > > > +    core->volume =
> > > > WL1273_DEFAULT_VOLUME;
> > > > > +    core->rx_frequency =
> > > > bands[core->band].bottom_frequency;
> > > > > +    core->tx_frequency =
> > > > bands[core->band].top_frequency;
> > > > > +
> > > > > +   
> dev_dbg(&client->dev,
> > > > "radio_band: %d\n", radio_band);
> > > > > +
> > > > > +   
> mutex_init(&core->lock);
> > > > > +
> > > > > +    pdata =
> > > > client->dev.platform_data;
> > > > > +    if (pdata) {
> > > > > +        r =
> > > > pdata->request_resources(client);
> > > > > +        if (r) {
> > > > > +
> > > > 
>    dev_err(&client->dev,
> > > > WL1273_FM_DRIVER_NAME
> > > > > +
> > > >         ":
> Cannot get platform
> > > > data\n");
> > > > > +
> > > >     goto err_new_mixer;
> > > > > +        }
> > > > > +
> > > > > +        r =
> > > > request_threaded_irq(client->irq, NULL,
> > > > > +
> > > >
> > > >     
> wl1273_fm_irq_thread_handler,
> > > > > +
> > > >
> > > >      IRQF_ONESHOT |
> > > > IRQF_TRIGGER_FALLING,
> > > > > +
> > > >
> > > >      "wl1273-fm", core);
> > > > > +        if (r <
> 0)
> > > > {
> > > > > +
> > > > 
>    dev_err(&client->dev,
> > > > WL1273_FM_DRIVER_NAME
> > > > > +
> > > >         ":
> Unable to register
> > > > IRQ handler\n");
> > > > > +
> > > >     goto
> err_request_irq;
> > > > > +        }
> > > > > +    } else {
> > > > > +
> > > > dev_err(&client->dev,
> WL1273_FM_DRIVER_NAME ":
> > > Core
> > > > WL1273 IRQ"
> > > > > +
> > > >     " not configured");
> > > > > +        r =
> -EINVAL;
> > > > > +        goto
> > > > err_new_mixer;
> > > > > +    }
> > > > > +
> > > > > +
> > > > init_completion(&core->busy);
> > > > > +
> > > >
> init_waitqueue_head(&core->read_queue);
> > > > > +
> > > > > +   
> i2c_set_clientdata(client, core);
> > > > > +
> > > > > +    if (pdata->children
> &
> > > > WL1273_RADIO_CHILD) {
> > > > > +        struct
> mfd_cell
> > > > *cell = &core->cells[children];
> > > > > +
> > > > dev_dbg(&client->dev, "%s: Have
> V4L2.\n",
> > > __func__);
> > > > > +       
> cell->name =
> > > > "wl1273_fm_radio";
> > > > > +
> > > > cell->platform_data = &core;
> > > > > +
> > > > cell->data_size = sizeof(core);
> > > > > +       
> children++;
> > > > > +    }
> > > > > +
> > > > > +    if (pdata->children
> &
> > > > WL1273_CODEC_CHILD) {
> > > > > +        struct
> mfd_cell
> > > > *cell = &core->cells[children];
> > > > > +
> > > > dev_dbg(&client->dev, "%s: Have
> codec.\n",
> > > > __func__);
> > > > > +       
> cell->name =
> > > > "wl1273_codec_audio";
> > > > > +
> > > > cell->platform_data = &core;
> > > > > +
> > > > cell->data_size = sizeof(core);
> > > > > +       
> children++;
> > > > > +    }
> > > > > +
> > > > > +    if (children) {
> > > > > +
> > > > dev_dbg(&client->dev, "%s: Have
> children.\n",
> > > > __func__);
> > > > > +        r =
> > > > mfd_add_devices(&client->dev, -1,
> > > core->cells,
> > > > > +
> > > >
> > > > children, NULL, 0);
> > > > > +    } else {
> > > > > +
> > > > dev_err(&client->dev, "No platform
> data found
> > > for
> > > > children.\n");
> > > > > +        r =
> -ENODEV;
> > > > > +    }
> > > > > +
> > > > > +    if (!r)
> > > > > +        return 0;
> > > > > +
> > > > > +   
> i2c_set_clientdata(client, NULL);
> > > > > +    kfree(core);
> > > > > +    free_irq(client->irq,
> core);
> > > > > +err_request_irq:
> > > > > +   
> pdata->free_resources();
> > > > > +err_new_mixer:
> > > > > +    kfree(core->buffer);
> > > > > +err_kmalloc:
> > > > > +    kfree(core);
> > > > > +   
> dev_dbg(&client->dev,
> > > > "%s\n", __func__);
> > > > > +
> > > > > +    return r;
> > > > > +}
> > > > > +
> > > > > +static struct i2c_driver
> wl1273_core_driver = {
> > > > > +    .driver = {
> > > > > +        .name =
> > > > WL1273_FM_DRIVER_NAME,
> > > > > +    },
> > > > > +    .probe =
> wl1273_core_probe,
> > > > > +    .id_table =
> > > > wl1273_driver_id_table,
> > > > > +    .remove =
> > > > __devexit_p(wl1273_core_remove),
> > > > > +};
> > > > > +
> > > > > +static int __init
> wl1273_core_init(void)
> > > > > +{
> > > > > +    int r;
> > > > > +
> > > > > +    r =
> > > > i2c_add_driver(&wl1273_core_driver);
> > > > > +    if (r) {
> > > > > +
> > > > pr_err(WL1273_FM_DRIVER_NAME
> > > > > +
> > > >    ": driver registration
> failed\n");
> > > > > +        return r;
> > > > > +    }
> > > > > +
> > > > > +    return 0;
> > > > > +}
> > > > > +
> > > > > +static void __exit
> wl1273_core_exit(void)
> > > > > +{
> > > > > +    flush_scheduled_work();
> > > > > +
> > > > > +
> > > > i2c_del_driver(&wl1273_core_driver);
> > > > > +}
> > > > > +late_initcall(wl1273_core_init);
> > > > > +module_exit(wl1273_core_exit);
> > > > > +
> > > > > +MODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@xxxxxxxxx>");
> > > > > +MODULE_DESCRIPTION(DRIVER_DESC);
> > > > > +MODULE_LICENSE("GPL");
> > > > > diff --git
> a/include/linux/mfd/wl1273-core.h
> > > > b/include/linux/mfd/wl1273-core.h
> > > > > new file mode 100644
> > > > > index 0000000..81c9743
> > > > > --- /dev/null
> > > > > +++ b/include/linux/mfd/wl1273-core.h
> > > > > @@ -0,0 +1,326 @@
> > > > > +/*
> > > > > + * include/media/radio/radio-wl1273.h
> > > > > + *
> > > > > + * Some definitions for the wl1273
> radio
> > > > receiver/transmitter chip.
> > > > > + *
> > > > > + * Copyright (C) Nokia Corporation
> > > > > + * Author: Matti J. Aaltonen <matti.j.aaltonen@xxxxxxxxx>
> > > > > + *
> > > > > + * This program is free software; you
> can
> > > > redistribute it and/or
> > > > > + * modify it under the terms of the
> GNU General
> > > > Public License
> > > > > + * version 2 as published by the Free
> Software
> > > > Foundation.
> > > > > + *
> > > > > + * This program is distributed in the
> hope that
> > > it
> > > > will be useful, but
> > > > > + * WITHOUT ANY WARRANTY; without even
> the
> > > implied
> > > > warranty of
> > > > > + * MERCHANTABILITY or FITNESS FOR A
> PARTICULAR
> > > > PURPOSE.  See the GNU
> > > > > + * General Public License for more
> details.
> > > > > + *
> > > > > + * You should have received a copy of
> the GNU
> > > General
> > > > Public License
> > > > > + * along with this program; if not,
> write to the
> > > Free
> > > > Software
> > > > > + * Foundation, Inc., 51 Franklin St,
> Fifth
> > > Floor,
> > > > Boston, MA
> > > > > + * 02110-1301 USA
> > > > > + */
> > > > > +
> > > > > +#ifndef RADIO_WL1273_H
> > > > > +#define RADIO_WL1273_H
> > > > > +
> > > > > +#include <linux/i2c.h>
> > > > > +#include <linux/mfd/core.h>
> > > > > +
> > > > > +#define WL1273_FM_DRIVER_NAME
> > > > "wl1273-fm"
> > > > > +#define RX71_FM_I2C_ADDR   
> 0x22
> > > > > +
> > > > > +#define WL1273_STEREO_GET
> > > >     0
> > > > > +#define WL1273_RSSI_LVL_GET
> > > >     1
> > > > > +#define WL1273_IF_COUNT_GET
> > > >     2
> > > > > +#define WL1273_FLAG_GET
> > > >         3
> > > > > +#define WL1273_RDS_SYNC_GET
> > > >     4
> > > > > +#define WL1273_RDS_DATA_GET
> > > >     5
> > > > > +#define WL1273_FREQ_SET
> > > >         10
> > > > > +#define WL1273_AF_FREQ_SET
> > > >     11
> > > > > +#define WL1273_MOST_MODE_SET
> > > >     12
> > > > > +#define WL1273_MOST_BLEND_SET
> > > >     13
> > > > > +#define WL1273_DEMPH_MODE_SET
> > > >     14
> > > > > +#define WL1273_SEARCH_LVL_SET
> > > >     15
> > > > > +#define WL1273_BAND_SET
> > > >         16
> > > > > +#define WL1273_MUTE_STATUS_SET
> > > >     17
> > > > > +#define WL1273_RDS_PAUSE_LVL_SET
> > > > 18
> > > > > +#define WL1273_RDS_PAUSE_DUR_SET
> > > > 19
> > > > > +#define WL1273_RDS_MEM_SET
> > > >     20
> > > > > +#define WL1273_RDS_BLK_B_SET
> > > >     21
> > > > > +#define WL1273_RDS_MSK_B_SET
> > > >     22
> > > > > +#define WL1273_RDS_PI_MASK_SET
> > > >     23
> > > > > +#define WL1273_RDS_PI_SET
> > > >     24
> > > > > +#define WL1273_RDS_SYSTEM_SET
> > > >     25
> > > > > +#define WL1273_INT_MASK_SET
> > > >     26
> > > > > +#define WL1273_SEARCH_DIR_SET
> > > >     27
> > > > > +#define WL1273_VOLUME_SET
> > > >     28
> > > > > +#define WL1273_AUDIO_ENABLE
> > > >     29
> > > > > +#define WL1273_PCM_MODE_SET
> > > >     30
> > > > > +#define WL1273_I2S_MODE_CONFIG_SET
> > > > 31
> > > > > +#define WL1273_POWER_SET
> > > >     32
> > > > > +#define WL1273_INTX_CONFIG_SET
> > > >     33
> > > > > +#define WL1273_PULL_EN_SET
> > > >     34
> > > > > +#define WL1273_HILO_SET
> > > >         35
> > > > > +#define WL1273_SWITCH2FREF
> > > >     36
> > > > > +#define WL1273_FREQ_DRIFT_REPORT
> > > > 37
> > > > > +
> > > > > +#define WL1273_PCE_GET
> > > >         40
> > > > > +#define WL1273_FIRM_VER_GET
> > > >     41
> > > > > +#define WL1273_ASIC_VER_GET
> > > >     42
> > > > > +#define WL1273_ASIC_ID_GET
> > > >     43
> > > > > +#define WL1273_MAN_ID_GET
> > > >     44
> > > > > +#define WL1273_TUNER_MODE_SET
> > > >     45
> > > > > +#define WL1273_STOP_SEARCH
> > > >     46
> > > > > +#define WL1273_RDS_CNTRL_SET
> > > >     47
> > > > > +
> > > > > +#define WL1273_WRITE_HARDWARE_REG
> > > > 100
> > > > > +#define WL1273_CODE_DOWNLOAD
> > > >     101
> > > > > +#define WL1273_RESET
> > > >         102
> > > > > +
> > > > > +#define WL1273_FM_POWER_MODE
> > > >     254
> > > > > +#define WL1273_FM_INTERRUPT
> > > >     255
> > > > > +
> > > > > +/* Transmitter API */
> > > > > +
> > > > > +#define WL1273_CHANL_SET
> > > >     55
> > > > > +#define WL1273_SCAN_SPACING_SET
> > > >     56
> > > > > +#define WL1273_REF_SET
> > > >         57
> > > > > +#define WL1273_POWER_ENB_SET
> > > >     90
> > > > > +#define WL1273_POWER_ATT_SET
> > > >     58
> > > > > +#define WL1273_POWER_LEV_SET
> > > >     59
> > > > > +#define WL1273_AUDIO_DEV_SET
> > > >     60
> > > > > +#define WL1273_PILOT_DEV_SET
> > > >     61
> > > > > +#define WL1273_RDS_DEV_SET
> > > >     62
> > > > > +#define WL1273_PUPD_SET
> > > >         91
> > > > > +#define WL1273_AUDIO_IO_SET
> > > >     63
> > > > > +#define WL1273_PREMPH_SET
> > > >     64
> > > > > +#define WL1273_MONO_SET
> > > >         66
> > > > > +#define WL1273_MUTE
> > > >         92
> > > > > +#define WL1273_MPX_LMT_ENABLE
> > > >     67
> > > > > +#define WL1273_PI_SET
> > > >         93
> > > > > +#define WL1273_ECC_SET
> > > >         69
> > > > > +#define WL1273_PTY
> > > >         70
> > > > > +#define WL1273_AF
> > > >         71
> > > > > +#define WL1273_DISPLAY_MODE
> > > >     74
> > > > > +#define WL1273_RDS_REP_SET
> > > >     77
> > > > > +#define WL1273_RDS_CONFIG_DATA_SET
> > > > 98
> > > > > +#define WL1273_RDS_DATA_SET
> > > >     99
> > > > > +#define WL1273_RDS_DATA_ENB
> > > >     94
> > > > > +#define WL1273_TA_SET
> > > >         78
> > > > > +#define WL1273_TP_SET
> > > >         79
> > > > > +#define WL1273_DI_SET
> > > >         80
> > > > > +#define WL1273_MS_SET
> > > >         81
> > > > > +#define WL1273_PS_SCROLL_SPEED
> > > >     82
> > > > > +#define WL1273_TX_AUDIO_LEVEL_TEST
> > > > 96
> > > > > +#define
> > > > WL1273_TX_AUDIO_LEVEL_TEST_THRESHOLD 
>   73
> > > > > +#define
> > > > WL1273_TX_AUDIO_INPUT_LEVEL_RANGE_SET 
>   54
> > > > > +#define WL1273_RX_ANTENNA_SELECT
> > > > 87
> > > > > +#define WL1273_I2C_DEV_ADDR_SET
> > > >     86
> > > > > +#define
> > > > WL1273_REF_ERR_CALIB_PARAM_SET
> > > >     88
> > > > > +#define
> > > > WL1273_REF_ERR_CALIB_PERIODICITY_SET 
>   89
> > > > > +#define WL1273_SOC_INT_TRIGGER
> > > >         52
> > > > > +#define WL1273_SOC_AUDIO_PATH_SET
> > > >     83
> > > > > +#define WL1273_SOC_PCMI_OVERRIDE
> > > >     84
> > > > > +#define WL1273_SOC_I2S_OVERRIDE
> > > >     85
> > > > > +#define
> > > > WL1273_RSSI_BLOCK_SCAN_FREQ_SET   
> 95
> > > > > +#define
> > > > WL1273_RSSI_BLOCK_SCAN_START   
> 97
> > > > > +#define
> > > > WL1273_RSSI_BLOCK_SCAN_DATA_GET 
>    5
> > > > > +#define
> > > > WL1273_READ_FMANT_TUNE_VALUE
> > > >     104
> > > > > +
> > > > > +#define WL1273_RDS_OFF
> > > >     0
> > > > > +#define WL1273_RDS_ON
> > > >     1
> > > > > +#define WL1273_RDS_RESET   
> 2
> > > > > +
> > > > > +#define WL1273_AUDIO_DIGITAL 
>   0
> > > > > +#define WL1273_AUDIO_ANALOG 
>   1
> > > > > +
> > > > > +#define WL1273_MODE_RX
> > > >     0
> > > > > +#define WL1273_MODE_TX
> > > >     1
> > > > > +#define WL1273_MODE_OFF
> > > >     2
> > > > > +#define WL1273_MODE_SUSPENDED 
>   3
> > > > > +
> > > > > +#define WL1273_RADIO_CHILD 
>   (1
> > > > << 0)
> > > > > +#define WL1273_CODEC_CHILD 
>   (1
> > > > << 1)
> > > > > +
> > > > > +#define WL1273_RX_MONO
> > > >     1
> > > > > +#define WL1273_RX_STEREO   
> 0
> > > > > +#define WL1273_TX_MONO
> > > >     0
> > > > > +#define WL1273_TX_STEREO   
> 1
> > > > > +
> > > > > +#define WL1273_MAX_VOLUME   
> 0xffff
> > > > > +#define WL1273_DEFAULT_VOLUME
> > > > 0x78b8
> > > > > +
> > > > > +/* I2S protocol, left channel first,
> data width
> > > 16
> > > > bits */
> > > > > +#define WL1273_PCM_DEF_MODE
> > > >     0x00
> > > > > +
> > > > > +/* Rx */
> > > > > +#define WL1273_AUDIO_ENABLE_I2S
> > > >     (1 << 0)
> > > > > +#define WL1273_AUDIO_ENABLE_ANALOG
> > > > (1 << 1)
> > > > > +
> > > > > +/* Tx */
> > > > > +#define WL1273_AUDIO_IO_SET_ANALOG
> > > > 0
> > > > > +#define WL1273_AUDIO_IO_SET_I2S
> > > >     1
> > > > > +
> > > > > +#define WL1273_POWER_SET_OFF
> > > >     0
> > > > > +#define WL1273_POWER_SET_FM
> > > >     (1 << 0)
> > > > > +#define WL1273_POWER_SET_RDS
> > > >     (1 << 1)
> > > > > +#define WL1273_POWER_SET_RETENTION
> > > > (1 << 4)
> > > > > +
> > > > > +#define WL1273_PUPD_SET_OFF
> > > >     0x00
> > > > > +#define WL1273_PUPD_SET_ON
> > > >     0x01
> > > > > +#define WL1273_PUPD_SET_RETENTION
> > > > 0x10
> > > > > +
> > > > > +/* I2S mode */
> > > > > +#define WL1273_IS2_WIDTH_32 
>   0x0
> > > > > +#define WL1273_IS2_WIDTH_40 
>   0x1
> > > > > +#define WL1273_IS2_WIDTH_22_23 
>   0x2
> > > > > +#define WL1273_IS2_WIDTH_23_22 
>   0x3
> > > > > +#define WL1273_IS2_WIDTH_48 
>   0x4
> > > > > +#define WL1273_IS2_WIDTH_50 
>   0x5
> > > > > +#define WL1273_IS2_WIDTH_60 
>   0x6
> > > > > +#define WL1273_IS2_WIDTH_64 
>   0x7
> > > > > +#define WL1273_IS2_WIDTH_80 
>   0x8
> > > > > +#define WL1273_IS2_WIDTH_96 
>   0x9
> > > > > +#define WL1273_IS2_WIDTH_128 
>   0xa
> > > > > +#define WL1273_IS2_WIDTH   
> 0xf
> > > > > +
> > > > > +#define WL1273_IS2_FORMAT_STD 
>   (0x0
> > > > << 4)
> > > > > +#define WL1273_IS2_FORMAT_LEFT 
>   (0x1
> > > > << 4)
> > > > > +#define WL1273_IS2_FORMAT_RIGHT
> > > > (0x2 << 4)
> > > > > +#define WL1273_IS2_FORMAT_USER 
>   (0x3
> > > > << 4)
> > > > > +
> > > > > +#define WL1273_IS2_MASTER   
> (0x0
> > > > << 6)
> > > > > +#define WL1273_IS2_SLAVEW   
> (0x1
> > > > << 6)
> > > > > +
> > > > > +#define
> > > > WL1273_IS2_TRI_AFTER_SENDING   
> (0x0 <<
> > > > 7)
> > > > > +#define
> > > > WL1273_IS2_TRI_ALWAYS_ACTIVE   
> (0x1 <<
> > > > 7)
> > > > > +
> > > > > +#define WL1273_IS2_SDOWS_RR 
>   (0x0
> > > > << 8)
> > > > > +#define WL1273_IS2_SDOWS_RF 
>   (0x1
> > > > << 8)
> > > > > +#define WL1273_IS2_SDOWS_FR 
>   (0x2
> > > > << 8)
> > > > > +#define WL1273_IS2_SDOWS_FF 
>   (0x3
> > > > << 8)
> > > > > +
> > > > > +#define WL1273_IS2_TRI_OPT 
>   (0x0
> > > > << 10)
> > > > > +#define WL1273_IS2_TRI_ALWAYS 
>   (0x1
> > > > << 10)
> > > > > +
> > > > > +#define WL1273_IS2_RATE_48K 
>   (0x0
> > > > << 12)
> > > > > +#define WL1273_IS2_RATE_44_1K 
>   (0x1
> > > > << 12)
> > > > > +#define WL1273_IS2_RATE_32K 
>   (0x2
> > > > << 12)
> > > > > +#define WL1273_IS2_RATE_22_05K 
>   (0x4
> > > > << 12)
> > > > > +#define WL1273_IS2_RATE_16K 
>   (0x5
> > > > << 12)
> > > > > +#define WL1273_IS2_RATE_12K 
>   (0x8
> > > > << 12)
> > > > > +#define WL1273_IS2_RATE_11_025 
>   (0x9
> > > > << 12)
> > > > > +#define WL1273_IS2_RATE_8K 
>   (0xa
> > > > << 12)
> > > > > +#define WL1273_IS2_RATE
> > > >     (0xf << 12)
> > > > > +
> > > > > +#define WL1273_I2S_DEF_MODE
> > > > (WL1273_IS2_WIDTH_32 | \
> > > > > +
> > > >
> > > >      WL1273_IS2_FORMAT_STD |
> \
> > > > > +
> > > >
> > > >      WL1273_IS2_MASTER | \
> > > > > +
> > > >
> > > >     
> WL1273_IS2_TRI_AFTER_SENDING |
> > > > \
> > > > > +
> > > >
> > > >      WL1273_IS2_SDOWS_RR | \
> > > > > +
> > > >
> > > >      WL1273_IS2_TRI_OPT | \
> > > > > +
> > > >
> > > >      WL1273_IS2_RATE_48K)
> > > > > +
> > > > > +/* Private IOCTL */
> > > > > +#define WL1273_CID_FM_BAND
> > > > (V4L2_CID_PRIVATE_BASE + 2)
> > > > > +
> > > > > +#define SCHAR_MIN (-128)
> > > > > +#define SCHAR_MAX 127
> > > > > +
> > > > > +#define WL1273_FR_EVENT
> > > >         (1
> << 0)
> > > > > +#define WL1273_BL_EVENT
> > > >         (1
> << 1)
> > > > > +#define WL1273_RDS_EVENT
> > > >     (1 << 2)
> > > > > +#define WL1273_BBLK_EVENT
> > > >     (1 << 3)
> > > > > +#define WL1273_LSYNC_EVENT
> > > >     (1 << 4)
> > > > > +#define WL1273_LEV_EVENT
> > > >     (1 << 5)
> > > > > +#define WL1273_IFFR_EVENT
> > > >     (1 << 6)
> > > > > +#define WL1273_PI_EVENT
> > > >         (1
> << 7)
> > > > > +#define WL1273_PD_EVENT
> > > >         (1
> << 8)
> > > > > +#define WL1273_STIC_EVENT
> > > >     (1 << 9)
> > > > > +#define WL1273_MAL_EVENT
> > > >     (1 << 10)
> > > > > +#define WL1273_POW_ENB_EVENT
> > > >     (1 << 11)
> > > > > +#define WL1273_SCAN_OVER_EVENT
> > > >     (1 << 12)
> > > > > +#define WL1273_ERROR_EVENT
> > > >     (1 << 13)
> > > > > +
> > > > > +#define TUNER_MODE_STOP_SEARCH
> > > >     0
> > > > > +#define TUNER_MODE_PRESET
> > > >     1
> > > > > +#define TUNER_MODE_AUTO_SEEK
> > > >     2
> > > > > +#define TUNER_MODE_AF
> > > >         3
> > > > > +#define TUNER_MODE_AUTO_SEEK_PI
> > > >     4
> > > > > +#define TUNER_MODE_AUTO_SEEK_BULK
> > > > 5
> > > > > +
> > > > > +/* Allowed modes */
> > > > > +#define WL1273_RX_ALLOWED   
> 0x01
> > > > > +#define WL1273_TX_ALLOWED   
> 0x02
> > > > > +#define WL1273_RXTX_ALLOWED
> > > > (WL1273_RX_ALLOWED | WL1273_TX_ALLOWED)
> > > > > +
> > > > > +struct band_info {
> > > > > +    u32 bottom_frequency;
> > > > > +    u32 top_frequency;
> > > > > +    u8 band;
> > > > > +};
> > > > > +
> > > > > +struct wl1273_fm_platform_data {
> > > > > +    int (*request_resources)
> (struct
> > > > i2c_client *client);
> > > > > +    void (*free_resources)
> (void);
> > > > > +    void (*enable) (void);
> > > > > +    void (*disable) (void);
> > > > > +
> > > > > +    u8 modes;
> > > > > +    unsigned int children;
> > > > > +};
> > > > > +
> > > > > +#define WL1273_FM_CORE_CELLS 
>   2
> > > > > +
> > > > > +/* Allowed modes */
> > > > > +#define WL1273_RX_ALLOWED   
> 0x01
> > > > > +#define WL1273_TX_ALLOWED   
> 0x02
> > > > > +#define WL1273_RXTX_ALLOWED
> > > > (WL1273_RX_ALLOWED | WL1273_TX_ALLOWED)
> > > > > +
> > > > > +struct wl1273_core {
> > > > > +    struct mfd_cell
> > > > cells[WL1273_FM_CORE_CELLS];
> > > > > +    struct i2c_client
> *i2c_dev;
> > > > > +
> > > > > +     u8
> allowed_modes;
> > > > > +    unsigned int mode;
> > > > > +    unsigned int
> preemphasis;
> > > > > +    unsigned int
> audio_mode;
> > > > > +    unsigned int spacing;
> > > > > +    unsigned int tx_power;
> > > > > +    unsigned int
> rx_frequency;
> > > > > +    unsigned int
> tx_frequency;
> > > > > +    unsigned int band;
> > > > > +    unsigned int i2s_mode;
> > > > > +    unsigned int
> channel_number;
> > > > > +    unsigned int
> number_of_bands;
> > > > > +    unsigned int volume;
> > > > > +
> > > > > +    const struct band_info
> *bands;
> > > > > +
> > > > > +    /* RDS */
> > > > > +    bool rds_on;
> > > > > +    struct delayed_work
> work;
> > > > > +
> > > > > +    wait_queue_head_t
> read_queue;
> > > > > +    struct mutex lock; /*
> for
> > > > serializing fm radio operations */
> > > > > +    struct completion busy;
> > > > > +
> > > > > +    unsigned char *buffer;
> > > > > +    unsigned int buf_size;
> > > > > +    unsigned int rd_index;
> > > > > +    unsigned int wr_index;
> > > > > +
> > > > > +    /* Selected interrupts
> */
> > > > > +    u16 irq_flags;
> > > > > +    u16 irq_received;
> > > > > +};
> > > > > +
> > > > > +int wl1273_fm_write_cmd(struct
> wl1273_core
> > > *core, u8
> > > > cmd, u16 param);
> > > > > +int wl1273_fm_write_data(struct
> wl1273_core
> > > *core, u8
> > > > *data, u16 len);
> > > > > +int wl1273_fm_read_reg(struct
> wl1273_core *core,
> > > u8
> > > > reg, u16 *value);
> > > > > +
> > > > > +int wl1273_fm_set_audio(struct
> wl1273_core
> > > *core,
> > > > unsigned int mode);
> > > > > +int wl1273_fm_set_volume(struct
> wl1273_core
> > > *core,
> > > > unsigned int volume);
> > > > > +
> > > > > +#endif    /* ifndef
> RADIO_WL1273_H */
> > > >
> > > > --
> > > > To unsubscribe from this list: send the
> line
> > > "unsubscribe
> > > > linux-media" in
> > > > the body of a message to majordomo@xxxxxxxxxxxxxxx
> > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > >
> > >
> > >
> > >
> > 
> > 
> 
> 
> 


--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux