diff options
Diffstat (limited to 'drivers/media/tuners')
-rw-r--r-- | drivers/media/tuners/Kconfig | 7 | ||||
-rw-r--r-- | drivers/media/tuners/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/tuners/si2157.c | 260 | ||||
-rw-r--r-- | drivers/media/tuners/si2157.h | 34 | ||||
-rw-r--r-- | drivers/media/tuners/si2157_priv.h | 37 | ||||
-rw-r--r-- | drivers/media/tuners/xc5000.c | 302 |
6 files changed, 496 insertions, 145 deletions
diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index a1284889cd15..22b6b8bb1d93 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig @@ -230,6 +230,13 @@ config MEDIA_TUNER_TUA9001 help Infineon TUA 9001 silicon tuner driver. +config MEDIA_TUNER_SI2157 + tristate "Silicon Labs Si2157 silicon tuner" + depends on MEDIA_SUPPORT && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + Silicon Labs Si2157 silicon tuner driver. + config MEDIA_TUNER_IT913X tristate "ITE Tech IT913x silicon tuner" depends on MEDIA_SUPPORT && I2C diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile index efe82a904b12..a6ff0c628dfa 100644 --- a/drivers/media/tuners/Makefile +++ b/drivers/media/tuners/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o obj-$(CONFIG_MEDIA_TUNER_E4000) += e4000.o obj-$(CONFIG_MEDIA_TUNER_FC2580) += fc2580.o obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o +obj-$(CONFIG_MEDIA_TUNER_SI2157) += si2157.o obj-$(CONFIG_MEDIA_TUNER_M88TS2022) += m88ts2022.o obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c new file mode 100644 index 000000000000..271a752cee54 --- /dev/null +++ b/drivers/media/tuners/si2157.c @@ -0,0 +1,260 @@ +/* + * Silicon Labs Si2157 silicon tuner driver + * + * Copyright (C) 2014 Antti Palosaari <crope@iki.fi> + * + * 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. + */ + +#include "si2157_priv.h" + +/* execute firmware command */ +static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd) +{ + int ret; + u8 buf[1]; + unsigned long timeout; + + mutex_lock(&s->i2c_mutex); + + if (cmd->len) { + /* write cmd and args for firmware */ + ret = i2c_master_send(s->client, cmd->args, cmd->len); + if (ret < 0) { + goto err_mutex_unlock; + } else if (ret != cmd->len) { + ret = -EREMOTEIO; + goto err_mutex_unlock; + } + } + + /* wait cmd execution terminate */ + #define TIMEOUT 80 + timeout = jiffies + msecs_to_jiffies(TIMEOUT); + while (!time_after(jiffies, timeout)) { + ret = i2c_master_recv(s->client, buf, 1); + if (ret < 0) { + goto err_mutex_unlock; + } else if (ret != 1) { + ret = -EREMOTEIO; + goto err_mutex_unlock; + } + + /* firmware ready? */ + if ((buf[0] >> 7) & 0x01) + break; + } + + dev_dbg(&s->client->dev, "%s: cmd execution took %d ms\n", __func__, + jiffies_to_msecs(jiffies) - + (jiffies_to_msecs(timeout) - TIMEOUT)); + + if (!(buf[0] >> 7) & 0x01) { + ret = -ETIMEDOUT; + goto err_mutex_unlock; + } else { + ret = 0; + } + +err_mutex_unlock: + mutex_unlock(&s->i2c_mutex); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int si2157_init(struct dvb_frontend *fe) +{ + struct si2157 *s = fe->tuner_priv; + + dev_dbg(&s->client->dev, "%s:\n", __func__); + + s->active = true; + + return 0; +} + +static int si2157_sleep(struct dvb_frontend *fe) +{ + struct si2157 *s = fe->tuner_priv; + + dev_dbg(&s->client->dev, "%s:\n", __func__); + + s->active = false; + + return 0; +} + +static int si2157_set_params(struct dvb_frontend *fe) +{ + struct si2157 *s = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret; + struct si2157_cmd cmd; + + dev_dbg(&s->client->dev, + "%s: delivery_system=%d frequency=%u bandwidth_hz=%u\n", + __func__, c->delivery_system, c->frequency, + c->bandwidth_hz); + + if (!s->active) { + ret = -EAGAIN; + goto err; + } + + /* configure? */ + cmd.args[0] = 0xc0; + cmd.args[1] = 0x00; + cmd.args[2] = 0x0c; + cmd.args[3] = 0x00; + cmd.args[4] = 0x00; + cmd.args[5] = 0x01; + cmd.args[6] = 0x01; + cmd.args[7] = 0x01; + cmd.args[8] = 0x01; + cmd.args[9] = 0x01; + cmd.args[10] = 0x01; + cmd.args[11] = 0x02; + cmd.args[12] = 0x00; + cmd.args[13] = 0x00; + cmd.args[14] = 0x01; + cmd.len = 15; + ret = si2157_cmd_execute(s, &cmd); + if (ret) + goto err; + + cmd.args[0] = 0x02; + cmd.len = 1; + ret = si2157_cmd_execute(s, &cmd); + if (ret) + goto err; + + cmd.args[0] = 0x01; + cmd.args[1] = 0x01; + cmd.len = 2; + ret = si2157_cmd_execute(s, &cmd); + if (ret) + goto err; + + /* set frequency */ + cmd.args[0] = 0x41; + cmd.args[1] = 0x00; + cmd.args[2] = 0x00; + cmd.args[3] = 0x00; + cmd.args[4] = (c->frequency >> 0) & 0xff; + cmd.args[5] = (c->frequency >> 8) & 0xff; + cmd.args[6] = (c->frequency >> 16) & 0xff; + cmd.args[7] = (c->frequency >> 24) & 0xff; + cmd.len = 8; + ret = si2157_cmd_execute(s, &cmd); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static const struct dvb_tuner_ops si2157_tuner_ops = { + .info = { + .name = "Silicon Labs Si2157", + .frequency_min = 110000000, + .frequency_max = 862000000, + }, + + .init = si2157_init, + .sleep = si2157_sleep, + .set_params = si2157_set_params, +}; + +static int si2157_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct si2157_config *cfg = client->dev.platform_data; + struct dvb_frontend *fe = cfg->fe; + struct si2157 *s; + struct si2157_cmd cmd; + int ret; + + s = kzalloc(sizeof(struct si2157), GFP_KERNEL); + if (!s) { + ret = -ENOMEM; + dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); + goto err; + } + + s->client = client; + s->fe = cfg->fe; + mutex_init(&s->i2c_mutex); + + /* check if the tuner is there */ + cmd.len = 0; + ret = si2157_cmd_execute(s, &cmd); + if (ret) + goto err; + + fe->tuner_priv = s; + memcpy(&fe->ops.tuner_ops, &si2157_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + i2c_set_clientdata(client, s); + + dev_info(&s->client->dev, + "%s: Silicon Labs Si2157 successfully attached\n", + KBUILD_MODNAME); + return 0; +err: + dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret); + kfree(s); + + return ret; +} + +static int si2157_remove(struct i2c_client *client) +{ + struct si2157 *s = i2c_get_clientdata(client); + struct dvb_frontend *fe = s->fe; + + dev_dbg(&client->dev, "%s:\n", __func__); + + memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); + fe->tuner_priv = NULL; + kfree(s); + + return 0; +} + +static const struct i2c_device_id si2157_id[] = { + {"si2157", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, si2157_id); + +static struct i2c_driver si2157_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "si2157", + }, + .probe = si2157_probe, + .remove = si2157_remove, + .id_table = si2157_id, +}; + +module_i2c_driver(si2157_driver); + +MODULE_DESCRIPTION("Silicon Labs Si2157 silicon tuner driver"); +MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/si2157.h b/drivers/media/tuners/si2157.h new file mode 100644 index 000000000000..f469a092b66b --- /dev/null +++ b/drivers/media/tuners/si2157.h @@ -0,0 +1,34 @@ +/* + * Silicon Labs Si2157 silicon tuner driver + * + * Copyright (C) 2014 Antti Palosaari <crope@iki.fi> + * + * 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. + */ + +#ifndef SI2157_H +#define SI2157_H + +#include <linux/kconfig.h> +#include "dvb_frontend.h" + +/* + * I2C address + * 0x60 + */ +struct si2157_config { + /* + * frontend + */ + struct dvb_frontend *fe; +}; + +#endif diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h new file mode 100644 index 000000000000..6cc6c6fdab7a --- /dev/null +++ b/drivers/media/tuners/si2157_priv.h @@ -0,0 +1,37 @@ +/* + * Silicon Labs Si2157 silicon tuner driver + * + * Copyright (C) 2014 Antti Palosaari <crope@iki.fi> + * + * 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. + */ + +#ifndef SI2157_PRIV_H +#define SI2157_PRIV_H + +#include "si2157.h" + +/* state struct */ +struct si2157 { + struct mutex i2c_mutex; + struct i2c_client *client; + struct dvb_frontend *fe; + bool active; +}; + +/* firmare command struct */ +#define SI2157_ARGLEN 30 +struct si2157_cmd { + u8 args[SI2157_ARGLEN]; + unsigned len; +}; + +#endif diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index 5cd09a681b6a..2b3d514be672 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -25,6 +25,7 @@ #include <linux/moduleparam.h> #include <linux/videodev2.h> #include <linux/delay.h> +#include <linux/workqueue.h> #include <linux/dvb/frontend.h> #include <linux/i2c.h> @@ -65,26 +66,25 @@ struct xc5000_priv { u16 pll_register_no; u8 init_status_supported; u8 fw_checksum_supported; + + struct dvb_frontend *fe; + struct delayed_work timer_sleep; }; /* Misc Defines */ #define MAX_TV_STANDARD 24 #define XC_MAX_I2C_WRITE_LENGTH 64 +/* Time to suspend after the .sleep callback is called */ +#define XC5000_SLEEP_TIME 5000 /* ms */ + /* Signal Types */ #define XC_RF_MODE_AIR 0 #define XC_RF_MODE_CABLE 1 -/* Result codes */ -#define XC_RESULT_SUCCESS 0 -#define XC_RESULT_RESET_FAILURE 1 -#define XC_RESULT_I2C_WRITE_FAILURE 2 -#define XC_RESULT_I2C_READ_FAILURE 3 -#define XC_RESULT_OUT_OF_RANGE 5 - /* Product id */ #define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 -#define XC_PRODUCT_ID_FW_LOADED 0x1388 +#define XC_PRODUCT_ID_FW_LOADED 0x1388 /* Registers */ #define XREG_INIT 0x00 @@ -152,16 +152,16 @@ struct xc5000_priv { */ struct XC_TV_STANDARD { - char *Name; - u16 AudioMode; - u16 VideoMode; + char *name; + u16 audio_mode; + u16 video_mode; }; /* Tuner standards */ #define MN_NTSC_PAL_BTSC 0 #define MN_NTSC_PAL_A2 1 #define MN_NTSC_PAL_EIAJ 2 -#define MN_NTSC_PAL_Mono 3 +#define MN_NTSC_PAL_MONO 3 #define BG_PAL_A2 4 #define BG_PAL_NICAM 5 #define BG_PAL_MONO 6 @@ -171,19 +171,19 @@ struct XC_TV_STANDARD { #define DK_PAL_NICAM 10 #define DK_PAL_MONO 11 #define DK_SECAM_A2DK1 12 -#define DK_SECAM_A2LDK3 13 -#define DK_SECAM_A2MONO 14 +#define DK_SECAM_A2LDK3 13 +#define DK_SECAM_A2MONO 14 #define L_SECAM_NICAM 15 #define LC_SECAM_NICAM 16 #define DTV6 17 #define DTV8 18 #define DTV7_8 19 #define DTV7 20 -#define FM_Radio_INPUT2 21 -#define FM_Radio_INPUT1 22 -#define FM_Radio_INPUT1_MONO 23 +#define FM_RADIO_INPUT2 21 +#define FM_RADIO_INPUT1 22 +#define FM_RADIO_INPUT1_MONO 23 -static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { +static struct XC_TV_STANDARD xc5000_standard[MAX_TV_STANDARD] = { {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020}, {"M/N-NTSC/PAL-A2", 0x0600, 0x8020}, {"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020}, @@ -249,7 +249,7 @@ static inline const struct xc5000_fw_cfg *xc5000_assign_firmware(int chip_id) static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force); static int xc5000_is_firmware_loaded(struct dvb_frontend *fe); static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val); -static int xc5000_TunerReset(struct dvb_frontend *fe); +static int xc5000_tuner_reset(struct dvb_frontend *fe); static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) { @@ -258,9 +258,9 @@ static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len); - return XC_RESULT_I2C_WRITE_FAILURE; + return -EREMOTEIO; } - return XC_RESULT_SUCCESS; + return 0; } #if 0 @@ -297,15 +297,10 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) } *val = (bval[0] << 8) | bval[1]; - return XC_RESULT_SUCCESS; -} - -static void xc_wait(int wait_ms) -{ - msleep(wait_ms); + return 0; } -static int xc5000_TunerReset(struct dvb_frontend *fe) +static int xc5000_tuner_reset(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; int ret; @@ -320,43 +315,43 @@ static int xc5000_TunerReset(struct dvb_frontend *fe) XC5000_TUNER_RESET, 0); if (ret) { printk(KERN_ERR "xc5000: reset failed\n"); - return XC_RESULT_RESET_FAILURE; + return ret; } } else { printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n"); - return XC_RESULT_RESET_FAILURE; + return -EINVAL; } - return XC_RESULT_SUCCESS; + return 0; } -static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData) +static int xc_write_reg(struct xc5000_priv *priv, u16 reg_addr, u16 i2c_data) { u8 buf[4]; - int WatchDogTimer = 100; + int watch_dog_timer = 100; int result; - buf[0] = (regAddr >> 8) & 0xFF; - buf[1] = regAddr & 0xFF; - buf[2] = (i2cData >> 8) & 0xFF; - buf[3] = i2cData & 0xFF; + buf[0] = (reg_addr >> 8) & 0xFF; + buf[1] = reg_addr & 0xFF; + buf[2] = (i2c_data >> 8) & 0xFF; + buf[3] = i2c_data & 0xFF; result = xc_send_i2c_data(priv, buf, 4); - if (result == XC_RESULT_SUCCESS) { + if (result == 0) { /* wait for busy flag to clear */ - while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) { + while ((watch_dog_timer > 0) && (result == 0)) { result = xc5000_readreg(priv, XREG_BUSY, (u16 *)buf); - if (result == XC_RESULT_SUCCESS) { + if (result == 0) { if ((buf[0] == 0) && (buf[1] == 0)) { /* busy flag cleared */ break; } else { - xc_wait(5); /* wait 5 ms */ - WatchDogTimer--; + msleep(5); /* wait 5 ms */ + watch_dog_timer--; } } } } - if (WatchDogTimer <= 0) - result = XC_RESULT_I2C_WRITE_FAILURE; + if (watch_dog_timer <= 0) + result = -EREMOTEIO; return result; } @@ -375,13 +370,13 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) len = i2c_sequence[index] * 256 + i2c_sequence[index+1]; if (len == 0x0000) { /* RESET command */ - result = xc5000_TunerReset(fe); + result = xc5000_tuner_reset(fe); index += 2; - if (result != XC_RESULT_SUCCESS) + if (result != 0) return result; } else if (len & 0x8000) { /* WAIT command */ - xc_wait(len & 0x7FFF); + msleep(len & 0x7FFF); index += 2; } else { /* Send i2c data whilst ensuring individual transactions @@ -404,7 +399,7 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) result = xc_send_i2c_data(priv, buf, nbytes_to_send); - if (result != XC_RESULT_SUCCESS) + if (result != 0) return result; pos += nbytes_to_send - 2; @@ -412,7 +407,7 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) index += len; } } - return XC_RESULT_SUCCESS; + return 0; } static int xc_initialize(struct xc5000_priv *priv) @@ -421,29 +416,29 @@ static int xc_initialize(struct xc5000_priv *priv) return xc_write_reg(priv, XREG_INIT, 0); } -static int xc_SetTVStandard(struct xc5000_priv *priv, - u16 VideoMode, u16 AudioMode, u8 RadioMode) +static int xc_set_tv_standard(struct xc5000_priv *priv, + u16 video_mode, u16 audio_mode, u8 radio_mode) { int ret; - dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, VideoMode, AudioMode); - if (RadioMode) { + dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode); + if (radio_mode) { dprintk(1, "%s() Standard = %s\n", __func__, - XC5000_Standard[RadioMode].Name); + xc5000_standard[radio_mode].name); } else { dprintk(1, "%s() Standard = %s\n", __func__, - XC5000_Standard[priv->video_standard].Name); + xc5000_standard[priv->video_standard].name); } - ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode); - if (ret == XC_RESULT_SUCCESS) - ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode); + ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode); + if (ret == 0) + ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode); return ret; } -static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode) +static int xc_set_signal_source(struct xc5000_priv *priv, u16 rf_mode) { dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode, rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); @@ -459,7 +454,7 @@ static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode) static const struct dvb_tuner_ops xc5000_tuner_ops; -static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz) +static int xc_set_rf_frequency(struct xc5000_priv *priv, u32 freq_hz) { u16 freq_code; @@ -467,7 +462,7 @@ static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz) if ((freq_hz > xc5000_tuner_ops.info.frequency_max) || (freq_hz < xc5000_tuner_ops.info.frequency_min)) - return XC_RESULT_OUT_OF_RANGE; + return -EINVAL; freq_code = (u16)(freq_hz / 15625); @@ -488,7 +483,7 @@ static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz) } -static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope) +static int xc_get_adc_envelope(struct xc5000_priv *priv, u16 *adc_envelope) { return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope); } @@ -496,14 +491,14 @@ static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope) static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz) { int result; - u16 regData; + u16 reg_data; u32 tmp; - result = xc5000_readreg(priv, XREG_FREQ_ERROR, ®Data); - if (result != XC_RESULT_SUCCESS) + result = xc5000_readreg(priv, XREG_FREQ_ERROR, ®_data); + if (result != 0) return result; - tmp = (u32)regData; + tmp = (u32)reg_data; (*freq_error_hz) = (tmp * 15625) / 1000; return result; } @@ -521,7 +516,7 @@ static int xc_get_version(struct xc5000_priv *priv, int result; result = xc5000_readreg(priv, XREG_VERSION, &data); - if (result != XC_RESULT_SUCCESS) + if (result != 0) return result; (*hw_majorversion) = (data >> 12) & 0x0F; @@ -539,14 +534,14 @@ static int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev) static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz) { - u16 regData; + u16 reg_data; int result; - result = xc5000_readreg(priv, XREG_HSYNC_FREQ, ®Data); - if (result != XC_RESULT_SUCCESS) + result = xc5000_readreg(priv, XREG_HSYNC_FREQ, ®_data); + if (result != 0) return result; - (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100; + (*hsync_freq_hz) = ((reg_data & 0x0fff) * 763)/100; return result; } @@ -570,19 +565,19 @@ static int xc_get_totalgain(struct xc5000_priv *priv, u16 *totalgain) return xc5000_readreg(priv, XREG_TOTALGAIN, totalgain); } -static u16 WaitForLock(struct xc5000_priv *priv) +static u16 wait_for_lock(struct xc5000_priv *priv) { - u16 lockState = 0; - int watchDogCount = 40; - - while ((lockState == 0) && (watchDogCount > 0)) { - xc_get_lock_status(priv, &lockState); - if (lockState != 1) { - xc_wait(5); - watchDogCount--; + u16 lock_state = 0; + int watch_dog_count = 40; + + while ((lock_state == 0) && (watch_dog_count > 0)) { + xc_get_lock_status(priv, &lock_state); + if (lock_state != 1) { + msleep(5); + watch_dog_count--; } } - return lockState; + return lock_state; } #define XC_TUNE_ANALOG 0 @@ -593,11 +588,11 @@ static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode) dprintk(1, "%s(%u)\n", __func__, freq_hz); - if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS) + if (xc_set_rf_frequency(priv, freq_hz) != 0) return 0; if (mode == XC_TUNE_ANALOG) { - if (WaitForLock(priv) == 1) + if (wait_for_lock(priv) == 1) found = 1; } @@ -607,7 +602,7 @@ static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode) static int xc_set_xtal(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; - int ret = XC_RESULT_SUCCESS; + int ret = 0; switch (priv->chip_id) { default: @@ -649,23 +644,22 @@ static int xc5000_fwupload(struct dvb_frontend *fe) priv->i2c_props.adap->dev.parent); if (ret) { printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); - ret = XC_RESULT_RESET_FAILURE; goto out; } else { printk(KERN_DEBUG "xc5000: firmware read %Zu bytes.\n", fw->size); - ret = XC_RESULT_SUCCESS; + ret = 0; } if (fw->size != desired_fw->size) { printk(KERN_ERR "xc5000: firmware incorrect size\n"); - ret = XC_RESULT_RESET_FAILURE; + ret = -EINVAL; } else { printk(KERN_INFO "xc5000: firmware uploading...\n"); ret = xc_load_i2c_sequence(fe, fw->data); - if (XC_RESULT_SUCCESS == ret) + if (0 == ret) ret = xc_set_xtal(fe); - if (XC_RESULT_SUCCESS == ret) + if (0 == ret) printk(KERN_INFO "xc5000: firmware upload complete...\n"); else printk(KERN_ERR "xc5000: firmware upload failed...\n"); @@ -695,9 +689,9 @@ static void xc_debug_dump(struct xc5000_priv *priv) * Frame Lines needs two frame times after initial lock * before it is valid. */ - xc_wait(100); + msleep(100); - xc_get_ADC_Envelope(priv, &adc_envelope); + xc_get_adc_envelope(priv, &adc_envelope); dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); xc_get_frequency_error(priv, &freq_error_hz); @@ -744,7 +738,7 @@ static int xc5000_set_params(struct dvb_frontend *fe) u32 freq = fe->dtv_property_cache.frequency; u32 delsys = fe->dtv_property_cache.delivery_system; - if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) { + if (xc_load_fw_and_init_tuner(fe, 0) != 0) { dprintk(1, "Unable to load firmware and init tuner\n"); return -EINVAL; } @@ -820,24 +814,24 @@ static int xc5000_set_params(struct dvb_frontend *fe) dprintk(1, "%s() frequency=%d (compensated to %d)\n", __func__, freq, priv->freq_hz); - ret = xc_SetSignalSource(priv, priv->rf_mode); - if (ret != XC_RESULT_SUCCESS) { + ret = xc_set_signal_source(priv, priv->rf_mode); + if (ret != 0) { printk(KERN_ERR - "xc5000: xc_SetSignalSource(%d) failed\n", + "xc5000: xc_set_signal_source(%d) failed\n", priv->rf_mode); return -EREMOTEIO; } - ret = xc_SetTVStandard(priv, - XC5000_Standard[priv->video_standard].VideoMode, - XC5000_Standard[priv->video_standard].AudioMode, 0); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); + ret = xc_set_tv_standard(priv, + xc5000_standard[priv->video_standard].video_mode, + xc5000_standard[priv->video_standard].audio_mode, 0); + if (ret != 0) { + printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n"); return -EREMOTEIO; } ret = xc_set_IF_frequency(priv, priv->if_khz); - if (ret != XC_RESULT_SUCCESS) { + if (ret != 0) { printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n", priv->if_khz); return -EIO; @@ -862,15 +856,15 @@ static int xc5000_is_firmware_loaded(struct dvb_frontend *fe) u16 id; ret = xc5000_readreg(priv, XREG_PRODUCT_ID, &id); - if (ret == XC_RESULT_SUCCESS) { + if (ret == 0) { if (id == XC_PRODUCT_ID_FW_NOT_LOADED) - ret = XC_RESULT_RESET_FAILURE; + ret = -ENOENT; else - ret = XC_RESULT_SUCCESS; + ret = 0; } dprintk(1, "%s() returns %s id = 0x%x\n", __func__, - ret == XC_RESULT_SUCCESS ? "True" : "False", id); + ret == 0 ? "True" : "False", id); return ret; } @@ -936,19 +930,19 @@ static int xc5000_set_tv_freq(struct dvb_frontend *fe, } tune_channel: - ret = xc_SetSignalSource(priv, priv->rf_mode); - if (ret != XC_RESULT_SUCCESS) { + ret = xc_set_signal_source(priv, priv->rf_mode); + if (ret != 0) { printk(KERN_ERR - "xc5000: xc_SetSignalSource(%d) failed\n", + "xc5000: xc_set_signal_source(%d) failed\n", priv->rf_mode); return -EREMOTEIO; } - ret = xc_SetTVStandard(priv, - XC5000_Standard[priv->video_standard].VideoMode, - XC5000_Standard[priv->video_standard].AudioMode, 0); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); + ret = xc_set_tv_standard(priv, + xc5000_standard[priv->video_standard].video_mode, + xc5000_standard[priv->video_standard].audio_mode, 0); + if (ret != 0) { + printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n"); return -EREMOTEIO; } @@ -966,7 +960,7 @@ tune_channel: /* PLL is unlocked, force reload of the firmware */ dprintk(1, "xc5000: PLL not locked (0x%x). Reloading...\n", pll_lock_status); - if (xc_load_fw_and_init_tuner(fe, 1) != XC_RESULT_SUCCESS) { + if (xc_load_fw_and_init_tuner(fe, 1) != 0) { printk(KERN_ERR "xc5000: Unable to reload fw\n"); return -EREMOTEIO; } @@ -993,11 +987,11 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe, } if (priv->radio_input == XC5000_RADIO_FM1) - radio_input = FM_Radio_INPUT1; + radio_input = FM_RADIO_INPUT1; else if (priv->radio_input == XC5000_RADIO_FM2) - radio_input = FM_Radio_INPUT2; + radio_input = FM_RADIO_INPUT2; else if (priv->radio_input == XC5000_RADIO_FM1_MONO) - radio_input = FM_Radio_INPUT1_MONO; + radio_input = FM_RADIO_INPUT1_MONO; else { dprintk(1, "%s() unknown radio input %d\n", __func__, priv->radio_input); @@ -1008,18 +1002,18 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe, priv->rf_mode = XC_RF_MODE_AIR; - ret = xc_SetTVStandard(priv, XC5000_Standard[radio_input].VideoMode, - XC5000_Standard[radio_input].AudioMode, radio_input); + ret = xc_set_tv_standard(priv, xc5000_standard[radio_input].video_mode, + xc5000_standard[radio_input].audio_mode, radio_input); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); + if (ret != 0) { + printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n"); return -EREMOTEIO; } - ret = xc_SetSignalSource(priv, priv->rf_mode); - if (ret != XC_RESULT_SUCCESS) { + ret = xc_set_signal_source(priv, priv->rf_mode); + if (ret != 0) { printk(KERN_ERR - "xc5000: xc_SetSignalSource(%d) failed\n", + "xc5000: xc_set_signal_source(%d) failed\n", priv->rf_mode); return -EREMOTEIO; } @@ -1044,7 +1038,7 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe, if (priv->i2c_props.adap == NULL) return -EINVAL; - if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) { + if (xc_load_fw_and_init_tuner(fe, 0) != 0) { dprintk(1, "Unable to load firmware and init tuner\n"); return -EINVAL; } @@ -1105,23 +1099,25 @@ static int xc5000_get_status(struct dvb_frontend *fe, u32 *status) static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force) { struct xc5000_priv *priv = fe->tuner_priv; - int ret = XC_RESULT_SUCCESS; + int ret = 0; u16 pll_lock_status; u16 fw_ck; - if (force || xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) { + cancel_delayed_work(&priv->timer_sleep); + + if (force || xc5000_is_firmware_loaded(fe) != 0) { fw_retry: ret = xc5000_fwupload(fe); - if (ret != XC_RESULT_SUCCESS) + if (ret != 0) return ret; msleep(20); if (priv->fw_checksum_supported) { if (xc5000_readreg(priv, XREG_FW_CHECKSUM, &fw_ck) - != XC_RESULT_SUCCESS) { + != 0) { dprintk(1, "%s() FW checksum reading failed.\n", __func__); goto fw_retry; @@ -1137,7 +1133,7 @@ fw_retry: /* Start the tuner self-calibration process */ ret |= xc_initialize(priv); - if (ret != XC_RESULT_SUCCESS) + if (ret != 0) goto fw_retry; /* Wait for calibration to complete. @@ -1145,10 +1141,10 @@ fw_retry: * I2C transactions until calibration is complete. This way we * don't have to rely on clock stretching working. */ - xc_wait(100); + msleep(100); if (priv->init_status_supported) { - if (xc5000_readreg(priv, XREG_INIT_STATUS, &fw_ck) != XC_RESULT_SUCCESS) { + if (xc5000_readreg(priv, XREG_INIT_STATUS, &fw_ck) != 0) { dprintk(1, "%s() FW failed reading init status.\n", __func__); goto fw_retry; @@ -1177,27 +1173,39 @@ fw_retry: return ret; } -static int xc5000_sleep(struct dvb_frontend *fe) +static void xc5000_do_timer_sleep(struct work_struct *timer_sleep) { + struct xc5000_priv *priv =container_of(timer_sleep, struct xc5000_priv, + timer_sleep.work); + struct dvb_frontend *fe = priv->fe; int ret; dprintk(1, "%s()\n", __func__); - /* Avoid firmware reload on slow devices */ - if (no_poweroff) - return 0; - /* According to Xceive technical support, the "powerdown" register was removed in newer versions of the firmware. The "supported" way to sleep the tuner is to pull the reset pin low for 10ms */ - ret = xc5000_TunerReset(fe); - if (ret != XC_RESULT_SUCCESS) { + ret = xc5000_tuner_reset(fe); + if (ret != 0) printk(KERN_ERR "xc5000: %s() unable to shutdown tuner\n", __func__); - return -EREMOTEIO; - } else - return XC_RESULT_SUCCESS; +} + +static int xc5000_sleep(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + + dprintk(1, "%s()\n", __func__); + + /* Avoid firmware reload on slow devices */ + if (no_poweroff) + return 0; + + schedule_delayed_work(&priv->timer_sleep, + msecs_to_jiffies(XC5000_SLEEP_TIME)); + + return 0; } static int xc5000_init(struct dvb_frontend *fe) @@ -1205,7 +1213,7 @@ static int xc5000_init(struct dvb_frontend *fe) struct xc5000_priv *priv = fe->tuner_priv; dprintk(1, "%s()\n", __func__); - if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) { + if (xc_load_fw_and_init_tuner(fe, 0) != 0) { printk(KERN_ERR "xc5000: Unable to initialise tuner\n"); return -EREMOTEIO; } @@ -1224,8 +1232,10 @@ static int xc5000_release(struct dvb_frontend *fe) mutex_lock(&xc5000_list_mutex); - if (priv) + if (priv) { + cancel_delayed_work(&priv->timer_sleep); hybrid_tuner_release_state(priv); + } mutex_unlock(&xc5000_list_mutex); @@ -1297,6 +1307,8 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, /* new tuner instance */ priv->bandwidth = 6000000; fe->tuner_priv = priv; + priv->fe = fe; + INIT_DELAYED_WORK(&priv->timer_sleep, xc5000_do_timer_sleep); break; default: /* existing tuner instance */ @@ -1327,7 +1339,7 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, /* Check if firmware has been loaded. It is possible that another instance of the driver has loaded the firmware. */ - if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != XC_RESULT_SUCCESS) + if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) goto fail; switch (id) { |