Add Freescale MC44S803 tuner driver
PATCH v2 1/1 Add Freescale MC44S803 tuner driver
---
Changes since v1:
- rebase against official linux tree. v1 was based against a local tree and didn't apply cleanly.
drivers/media/common/tuners/Kconfig | 8 + drivers/media/common/tuners/Makefile | 1 + drivers/media/common/tuners/mc44s803.c | 366 +++++++++++++++++++++++++++ drivers/media/common/tuners/mc44s803.h | 46 ++++ drivers/media/common/tuners/mc44s803_priv.h | 208 +++++++++++++++ 5 files changed, 629 insertions(+), 0 deletions(-) create mode 100644 drivers/media/common/tuners/mc44s803.c create mode 100644 drivers/media/common/tuners/mc44s803.h create mode 100644 drivers/media/common/tuners/mc44s803_priv.h
drivers/media/common/tuners/Kconfig +8 -0
@@ -29,6 +29,7 @@ config MEDIA_TUNER select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMIZE select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMIZE menuconfig MEDIA_TUNER_CUSTOMIZE bool "Customize analog and hybrid tuner modules to build"
@@ -164,4 +165,11 @@ config MEDIA_TUNER_MXL5007T help A driver for the silicon tuner MxL5007T from MaxLinear. +config MEDIA_TUNER_MC44S803 + tristate "Freescale MC44S803 Low Power CMOS Broadband tuners" + depends on VIDEO_MEDIA && I2C + default m if DVB_FE_CUSTOMISE + help + Say Y here to support the Freescale MC44S803 based tuners + endif # MEDIA_TUNER_CUSTOMIZE
drivers/media/common/tuners/Makefile +1 -0
@@ -22,6 +22,7 @@ obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o +obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
drivers/media/common/tuners/mc44s803.c new file +366 -0
366 lines not on this page · raw message
drivers/media/common/tuners/mc44s803.h new file +46 -0
46 lines not on this page · raw message
drivers/media/common/tuners/mc44s803_priv.h new file +208 -0
208 lines not on this page · raw message
Signature · 1 line
1.5.6.5
hi Jochen,
Quoted 2 lines · Jochen Friedrich
Changes since v1:
- rebase against official linux tree. v1 was based against a local tree and didn't apply cleanly.
Now it applies cleanly, but didn't compile. Some header file is missing.
Antti
CC [M] /home/crope/linuxtv/code/af9015/81/v4l-dvb/v4l/mxl5007t.o
CC [M] /home/crope/linuxtv/code/af9015/81/v4l-dvb/v4l/mc44s803.o/home/crope/linuxtv/code/af9015/81/v4l-dvb/v4l/mc44s803.c: In function 'mc44s803_attach':/home/crope/linuxtv/code/af9015/81/v4l-dvb/v4l/mc44s803.c:339: error: 'KERN_ERROR' undeclared (first use in this function) /home/crope/linuxtv/code/af9015/81/v4l-dvb/v4l/mc44s803.c:339: error: (Each undeclared identifier is reported only once /home/crope/linuxtv/code/af9015/81/v4l-dvb/v4l/mc44s803.c:339: error: for each function it appears in.) /home/crope/linuxtv/code/af9015/81/v4l-dvb/v4l/mc44s803.c:339: error: expected ')' before string constant make[3]: *** [/home/crope/linuxtv/code/af9015/81/v4l-dvb/v4l/mc44s803.o] Error 1
make[2]: *** [_module_/home/crope/linuxtv/code/af9015/81/v4l-dvb/v4l] Error 2
make[2]: Leaving directory `/usr/src/kernels/2.6.27.9-159.fc10.x86_64'
make[1]: *** [default] Error 2
make[1]: Leaving directory `/home/crope/linuxtv/code/af9015/81/v4l-dvb/v4l'
make: *** [all] Error 2
[crope@localhost v4l-dvb]$
Signature · 1 line
http://palosaari.fi/
Hi Antti,
Quoted 5 lines
Now it applies cleanly, but didn't compile.
/home/crope/linuxtv/code/af9015/81/v4l-dvb/v4l/mc44s803.c:339: error:
'KERN_ERROR' undeclared (first use in this function)
Ouch, forgot to commit the fix for this typo:
s/KERN_ERROR/KERN_ERR/
v3 will follow.
Thanks,
Jochen
Quoted 364 lines · Jochen Friedrich
Signed-off-by Jochen Friedrich <[email protected]>---
Changes since v1:
- rebase against official linux tree. v1 was based against a local tree and didn't apply cleanly.drivers/media/common/tuners/Kconfig | 8 + drivers/media/common/tuners/Makefile | 1 + drivers/media/common/tuners/mc44s803.c | 366 +++++++++++++++++++++++++++ drivers/media/common/tuners/mc44s803.h | 46 ++++ drivers/media/common/tuners/mc44s803_priv.h | 208 +++++++++++++++ 5 files changed, 629 insertions(+), 0 deletions(-) create mode 100644 drivers/media/common/tuners/mc44s803.c create mode 100644 drivers/media/common/tuners/mc44s803.h create mode 100644 drivers/media/common/tuners/mc44s803_priv.hdrivers/media/common/tuners/Kconfig +8
-0@@ -29,6 +29,7 @@ config MEDIA_TUNER select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMIZE select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMIZE menuconfig MEDIA_TUNER_CUSTOMIZE bool "Customize analog and hybrid tuner modules to build"@@ -164,4 +165,11 @@ config MEDIA_TUNER_MXL5007T help A driver for the silicon tuner MxL5007T from MaxLinear. +config MEDIA_TUNER_MC44S803 + tristate "Freescale MC44S803 Low Power CMOS Broadband tuners" + depends on VIDEO_MEDIA && I2C + default m if DVB_FE_CUSTOMISE + help + Say Y here to support the Freescale MC44S803 based tuners + endif # MEDIA_TUNER_CUSTOMIZEdrivers/media/common/tuners/Makefile +1
-0@@ -22,6 +22,7 @@ obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o +obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontendsdrivers/media/common/tuners/mc44s803.c new file +305
-0@@ -0,0 +1,366 @@ +/* +* Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner +* +* Copyright (c) 2009 Jochen Friedrich <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* 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., 675 Mass Ave, Cambridge, MA 02139, USA.= +*/ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/dvb/frontend.h> +#include <linux/i2c.h> + +#include "dvb_frontend.h" + +#include "mc44s803.h" +#include "mc44s803_priv.h" + +/* Writes a single register */ +static int mc44s803_writereg (struct mc44s803_priv *priv,u32 val) +{ +u8 buf[3 ]; +struct i2c_msg msg = { + .addr = priv->cfg->i2c_address, .flags =0 , .buf = buf, .len =3 + }; + + buf[0 ] = (val &0xFF0000 ) >>16 ; + buf[1 ] = (val &0xFF00 ) >>8 ; + buf[2 ] = (val &0xFF ); + +if (i2c_transfer (priv->i2c, &msg,1 ) !=1 ) { +printk (KERN_WARNING "mc44s803 I2C write failed\n" ); +return -EREMOTEIO ; + } +return 0 ; +} + +/* Reads a single register */ +static int mc44s803_readreg (struct mc44s803_priv *priv,u8 reg,u32 *val) +{ +u32 wval; +u8 buf[3 ]; +u8 ret; +struct i2c_msg msg[] = { + { .addr = priv->cfg->i2c_address, .flags =I2C_M_RD , + .buf = buf, .len =3 }, + }; + + wval =MC44S803_REG_SM (MC44S803_REG_DATAREG ,MC44S803_ADDR ) | +MC44S803_REG_SM (reg,MC44S803_D ); + + ret =mc44s803_writereg (priv, wval); +if (ret) +return ret; + +if (i2c_transfer (priv->i2c, msg,1 ) !=1 ) { +printk (KERN_WARNING "mc44s803 I2C read failed\n" ); +return -EREMOTEIO ; + } + + *val = (buf[0 ] <<16 ) | (buf[1 ] <<8 ) | buf[2 ]; + +return 0 ; +} + +static int mc44s803_release (struct dvb_frontend *fe) +{ +struct mc44s803_priv *priv = fe->tuner_priv; + + fe->tuner_priv =NULL ; +kfree (priv); + +return 0 ; +} + +static int mc44s803_init (struct dvb_frontend *fe) +{ +struct mc44s803_priv *priv = fe->tuner_priv; +u32 val; +int err; + +if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl (fe,1 ); + +/* Reset chip */ + val =MC44S803_REG_SM (MC44S803_REG_RESET ,MC44S803_ADDR ) | +MC44S803_REG_SM (1 ,MC44S803_RS ); + + err =mc44s803_writereg (priv, val); +if (err) + goto exit; + + val =MC44S803_REG_SM (MC44S803_REG_RESET ,MC44S803_ADDR ); + + err =mc44s803_writereg (priv, val); +if (err) + goto exit; + +/* Power Up and Start Osc */ + + val =MC44S803_REG_SM (MC44S803_REG_REFOSC ,MC44S803_ADDR ) | +MC44S803_REG_SM (0xC0 ,MC44S803_REFOSC ) | +MC44S803_REG_SM (1 ,MC44S803_OSCSEL ); + + err =mc44s803_writereg (priv, val); +if (err) + goto exit; + + val =MC44S803_REG_SM (MC44S803_REG_POWER ,MC44S803_ADDR ) | +MC44S803_REG_SM (0x200 ,MC44S803_POWER ); + + err =mc44s803_writereg (priv, val); +if (err) + goto exit; + +msleep (10 ); + + val =MC44S803_REG_SM (MC44S803_REG_REFOSC ,MC44S803_ADDR ) | +MC44S803_REG_SM (0x40 ,MC44S803_REFOSC ) | +MC44S803_REG_SM (1 ,MC44S803_OSCSEL ); + + err =mc44s803_writereg (priv, val); +if (err) + goto exit; + +msleep (20 ); + +/* Setup Mixer */ + + val =MC44S803_REG_SM (MC44S803_REG_MIXER ,MC44S803_ADDR ) | +MC44S803_REG_SM (1 ,MC44S803_TRI_STATE ) | +MC44S803_REG_SM (0x7F ,MC44S803_MIXER_RES ); + + err =mc44s803_writereg (priv, val); +if (err) + goto exit; + +/* Setup Cirquit Adjust */ + + val =MC44S803_REG_SM (MC44S803_REG_CIRCADJ ,MC44S803_ADDR ) | +MC44S803_REG_SM (1 ,MC44S803_G1 ) | +MC44S803_REG_SM (1 ,MC44S803_G3 ) | +MC44S803_REG_SM (0x3 ,MC44S803_CIRCADJ_RES ) | +MC44S803_REG_SM (1 ,MC44S803_G6 ) | +MC44S803_REG_SM (priv->cfg->dig_out,MC44S803_S1 ) | +MC44S803_REG_SM (0x3 ,MC44S803_LP ) | +MC44S803_REG_SM (1 ,MC44S803_CLRF ) | +MC44S803_REG_SM (1 ,MC44S803_CLIF ); + + err =mc44s803_writereg (priv, val); +if (err) + goto exit; + + val =MC44S803_REG_SM (MC44S803_REG_CIRCADJ ,MC44S803_ADDR ) | +MC44S803_REG_SM (1 ,MC44S803_G1 ) | +MC44S803_REG_SM (1 ,MC44S803_G3 ) | +MC44S803_REG_SM (1 ,MC44S803_G6 ) | +MC44S803_REG_SM (priv->cfg->dig_out,MC44S803_S1 ) | +MC44S803_REG_SM (0x3 ,MC44S803_LP ); + + err =mc44s803_writereg (priv, val); +if (err) + goto exit; + +/* Setup Digtune */ + + val =MC44S803_REG_SM (MC44S803_REG_DIGTUNE ,MC44S803_ADDR ) | +MC44S803_REG_SM (3 ,MC44S803_XOD ); + + err =mc44s803_writereg (priv, val); +if (err) + goto exit; + +/* Setup AGC */ + + val =MC44S803_REG_SM (MC44S803_REG_LNAAGC ,MC44S803_ADDR ) | +MC44S803_REG_SM (1 ,MC44S803_AT1 ) | +MC44S803_REG_SM (1 ,MC44S803_AT2 ) | +MC44S803_REG_SM (1 ,MC44S803_AGC_AN_DIG ) | +MC44S803_REG_SM (1 ,MC44S803_AGC_READ_EN ) | +MC44S803_REG_SM (1 ,MC44S803_LNA0 ); + + err =mc44s803_writereg (priv, val); +if (err) + goto exit; + +if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl (fe,0 ); +return 0 ; + +exit: +if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl (fe,0 ); + +printk (KERN_WARNING "mc44s803: I/O Error\n" ); +return err; +} + +static int mc44s803_set_params (struct dvb_frontend *fe, +struct dvb_frontend_parameters *params) +{ +struct mc44s803_priv *priv = fe->tuner_priv; +u32 r1, r2, n1, n2, lo1, lo2, freq, val; +int err; + + priv->frequency = params->frequency; + + r1 =MC44S803_OSC /1000000 ; + r2 =MC44S803_OSC /100000 ; + + n1 = (params->frequency +MC44S803_IF1 +500000 ) /1000000 ; + freq =MC44S803_OSC / r1 * n1; + lo1 = ((60 * n1) + (r1 /2 )) / r1; + freq = freq - params->frequency; + + n2 = (freq -MC44S803_IF2 +50000 ) /100000 ; + lo2 = ((60 * n2) + (r2 /2 )) / r2; + +if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl (fe,1 ); + + val =MC44S803_REG_SM (MC44S803_REG_REFDIV ,MC44S803_ADDR ) | +MC44S803_REG_SM (r1-1 ,MC44S803_R1 ) | +MC44S803_REG_SM (r2-1 ,MC44S803_R2 ) | +MC44S803_REG_SM (1 ,MC44S803_REFBUF_EN ); + + err =mc44s803_writereg (priv, val); +if (err) + goto exit; + + val =MC44S803_REG_SM (MC44S803_REG_LO1 ,MC44S803_ADDR ) | +MC44S803_REG_SM (n1-2 ,MC44S803_LO1 ); + + err =mc44s803_writereg (priv, val); +if (err) + goto exit; + + val =MC44S803_REG_SM (MC44S803_REG_LO2 ,MC44S803_ADDR ) | +MC44S803_REG_SM (n2-2 ,MC44S803_LO2 ); + + err =mc44s803_writereg (priv, val); +if (err) + goto exit; + + val =MC44S803_REG_SM (MC44S803_REG_DIGTUNE ,MC44S803_ADDR ) | +MC44S803_REG_SM (1 ,MC44S803_DA ) | +MC44S803_REG_SM (lo1,MC44S803_LO_REF ) | +MC44S803_REG_SM (1 ,MC44S803_AT ); + + err =mc44s803_writereg (priv, val); +if (err) + goto exit; + + val =MC44S803_REG_SM (MC44S803_REG_DIGTUNE ,MC44S803_ADDR ) | +MC44S803_REG_SM (2 ,MC44S803_DA ) | +MC44S803_REG_SM (lo2,MC44S803_LO_REF ) | +MC44S803_REG_SM (1 ,MC44S803_AT ); + + err =mc44s803_writereg (priv, val); +if (err) + goto exit; + +if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl (fe,0 ); + +return 0 ; + +exit: +if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl (fe,0 ); + +printk (KERN_WARNING "mc44s803: I/O Error\n" ); +return err; +} + +static int mc44s803_get_frequency (struct dvb_frontend *fe,u32 *frequency) +{ +struct mc44s803_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; +return 0 ; +} + +static const struct dvb_tuner_ops mc44s803_tuner_ops = { + .info = { + .name ="Freescale MC44S803" , + .frequency_min =48000000 , + .frequency_max =1000000000 , + .frequency_step =100000 , + }, + + .release = mc44s803_release, + .init = mc44s803_init,
drivers/media/common/tuners/mc44s803.c line 315
Quoted 10 lines
drivers/media/common/tuners/mc44s803.c new file +10
-0+ .set_params = mc44s803_set_params, + .get_frequency = mc44s803_get_frequency +}; + +/* This functions tries to identify a MC44S803 tuner by reading the ID +register. This is hasty. */ +struct dvb_frontend *mc44s803_attach (struct dvb_frontend *fe, +struct i2c_adapter *i2c,struct mc44s803_config *cfg) +{ +struct mc44s803_priv *priv =NULL ;
Do you really need *priv set to NULL here ?
drivers/media/common/tuners/mc44s803.c line 323
Quoted 8 lines
drivers/media/common/tuners/mc44s803.c new file +8
-0+u32 reg; +u8 ret, id; + + reg =0 ; + + priv =kzalloc (sizeof (struct mc44s803_priv ),GFP_KERNEL ); +if (priv ==NULL ) +return NULL ;
Maybe return -ENOMEM; ? I don't sure about return NULL, may be your variant is right.
Quoted 5 lines
drivers/media/common/tuners/mc44s803.c new file +5
-0+ priv->cfg = cfg; + priv->i2c = i2c; + priv->fe = fe; + +if (fe->ops.i2c_gate_ctrl)
drivers/media/common/tuners/mc44s803.c line 339
Quoted 10 lines
drivers/media/common/tuners/mc44s803.c new file +10
-0+ fe->ops.i2c_gate_ctrl (fe,1 );/* open i2c_gate */ + + ret =mc44s803_readreg (priv,MC44S803_REG_ID , ®); +if (ret) + goto error; + + id =MC44S803_REG_MS (reg,MC44S803_ID ); + +if (id !=0x14 ) { + printk(KERN_ERROR "MC44S803: unsupported ID "
You pass the name of driver directly to printk messages in few places. Is it better to use such approach:
#define MC44S803_DRIVER_NAME "mc44s803"
printk (KERN_ERR MC44S803_DRIVER_NAME ": something\n");
?
What do you think?
Quoted 11 lines
drivers/media/common/tuners/mc44s803.c new file +11
-0+ "(%x should be 0x14)\n", id); + goto error; + } + +printk (KERN_INFO "MC44S803: successfully identified (ID = %x)\n" , id); +memcpy (&fe->ops.tuner_ops, &mc44s803_tuner_ops, +sizeof (struct dvb_tuner_ops )); + + fe->tuner_priv = priv; + +if (fe->ops.i2c_gate_ctrl)
drivers/media/common/tuners/mc44s803.c line 360
Quoted 10 lines
drivers/media/common/tuners/mc44s803.c new file +10
-0+ fe->ops.i2c_gate_ctrl (fe,0 );/* close i2c_gate */ + +return fe; + +error: +if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl (fe,0 );/* close i2c_gate */ + +kfree (priv); +return NULL ;
I'm not sure is it right to return NULL here.. May be some negative error number ?
<snip>
Signature · 1 line
Best regards, Klimov Alexey
Hi Alexey,
Quoted 8 lines
drivers/media/common/tuners/mc44s803.c line 315
Quoted 6 lines
drivers/media/common/tuners/mc44s803.c new file +6
-0+/* This functions tries to identify a MC44S803 tuner by reading the ID +register. This is hasty. */ +struct dvb_frontend *mc44s803_attach (struct dvb_frontend *fe, +struct i2c_adapter *i2c,struct mc44s803_config *cfg) +{ +struct mc44s803_priv *priv =NULL ;Do you really need *priv set to NULL here ?
No, it's not needed. Will remove.
Quoted 6 lines
drivers/media/common/tuners/mc44s803.c line 323
Quoted 3 lines
drivers/media/common/tuners/mc44s803.c new file +3
-0+ priv =kzalloc (sizeof (struct mc44s803_priv ),GFP_KERNEL ); +if (priv ==NULL ) +return NULL ;Maybe return
-ENOMEM; ? I don't sure about return NULL, may be your variant is right.
NULL is correct here. All tuners are supposed to return NULL on an error during attach().
Quoted 11 lines
drivers/media/common/tuners/mc44s803.c line 339
Quoted 2 lines
drivers/media/common/tuners/mc44s803.c new file +2
-0+if (id !=0x14 ) { + printk(KERN_ERROR "MC44S803: unsupported ID "You pass the name of driver directly to printk messages in few places. Is it better to use such approach:
#defineMC44S803_DRIVER_NAME"mc44s803"printk (
KERN_ERRMC44S803_DRIVER_NAME": something\n");?
What do you think?
You're right.
Thanks for your comments.
Jochen