* [PATCH v2 1/2] [media] lgdt3306a: support i2c mux for use by em28xx @ 2016-12-18 2:55 Kevin Cheng 2017-01-09 11:46 ` Hans Verkuil 0 siblings, 1 reply; 5+ messages in thread From: Kevin Cheng @ 2016-12-18 2:55 UTC (permalink / raw) To: linux-media; +Cc: Linux Media Mailing List Adds an i2c mux to the lgdt3306a demodulator. This was done to support the Hauppauge WinTV-dualHD 01595 USB TV tuner (em28xx), which utilizes two si2157 tuners behind gate control. Signed-off-by: Kevin Cheng <kcheng@gmail.com> --- drivers/media/dvb-frontends/Kconfig | 2 +- drivers/media/dvb-frontends/lgdt3306a.c | 108 ++++++++++++++++++++++++++++++++ drivers/media/dvb-frontends/lgdt3306a.h | 4 ++ 3 files changed, 113 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index c841fa1..16f9afa 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -619,7 +619,7 @@ config DVB_LGDT3305 config DVB_LGDT3306A tristate "LG Electronics LGDT3306A based" - depends on DVB_CORE && I2C + depends on DVB_CORE && I2C && I2C_MUX default m if !MEDIA_SUBDRV_AUTOSELECT help An ATSC 8VSB and QAM-B 64/256 demodulator module. Say Y when you want diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index 19dca46..b191e01 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -22,6 +22,7 @@ #include <linux/dvb/frontend.h> #include "dvb_math.h" #include "lgdt3306a.h" +#include <linux/i2c-mux.h> static int debug; @@ -65,6 +66,8 @@ struct lgdt3306a_state { enum fe_modulation current_modulation; u32 current_frequency; u32 snr; + + struct i2c_mux_core *muxc; }; /* @@ -2131,6 +2134,111 @@ static const struct dvb_frontend_ops lgdt3306a_ops = { .search = lgdt3306a_search, }; +static int lgdt3306a_select(struct i2c_mux_core *muxc, u32 chan) +{ + struct i2c_client *client = i2c_mux_priv(muxc); + struct lgdt3306a_state *state = i2c_get_clientdata(client); + + return lgdt3306a_i2c_gate_ctrl(&state->frontend, 1); +} + +static int lgdt3306a_deselect(struct i2c_mux_core *muxc, u32 chan) +{ + struct i2c_client *client = i2c_mux_priv(muxc); + struct lgdt3306a_state *state = i2c_get_clientdata(client); + + return lgdt3306a_i2c_gate_ctrl(&state->frontend, 0); +} + +static int lgdt3306a_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct lgdt3306a_config *config = client->dev.platform_data; + struct lgdt3306a_state *state; + struct dvb_frontend *fe; + int ret; + + config = kzalloc(sizeof(struct lgdt3306a_config), GFP_KERNEL); + if (config == NULL) { + ret = -ENOMEM; + goto fail; + } + + memcpy(config, client->dev.platform_data, + sizeof(struct lgdt3306a_config)); + + config->i2c_addr = client->addr; + fe = lgdt3306a_attach(config, client->adapter); + if (fe == NULL) { + ret = -ENODEV; + goto err_fe; + } + + i2c_set_clientdata(client, fe->demodulator_priv); + state = fe->demodulator_priv; + + /* create mux i2c adapter for tuner */ + state->muxc = i2c_mux_alloc(client->adapter, &client->dev, + 1, 0, I2C_MUX_LOCKED, + lgdt3306a_select, lgdt3306a_deselect); + if (!state->muxc) { + ret = -ENOMEM; + goto err_kfree; + } + state->muxc->priv = client; + ret = i2c_mux_add_adapter(state->muxc, 0, 0, 0); + if (ret) + goto err_kfree; + + /* create dvb_frontend */ + fe->ops.i2c_gate_ctrl = NULL; + *config->i2c_adapter = state->muxc->adapter[0]; + *config->fe = fe; + + return 0; + +err_kfree: + kfree(state); +err_fe: + kfree(config); +fail: + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; +} + +static int lgdt3306a_remove(struct i2c_client *client) +{ + struct lgdt3306a_state *state = i2c_get_clientdata(client); + + i2c_mux_del_adapters(state->muxc); + + state->frontend.ops.release = NULL; + state->frontend.demodulator_priv = NULL; + + kfree(state->cfg); + kfree(state); + + return 0; +} + +static const struct i2c_device_id lgdt3306a_id_table[] = { + {"lgdt3306a", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, lgdt3306a_id_table); + +static struct i2c_driver lgdt3306a_driver = { + .driver = { + .name = "lgdt3306a", + .suppress_bind_attrs = true, + }, + .probe = lgdt3306a_probe, + .remove = lgdt3306a_remove, + .id_table = lgdt3306a_id_table, +}; + +module_i2c_driver(lgdt3306a_driver); + MODULE_DESCRIPTION("LG Electronics LGDT3306A ATSC/QAM-B Demodulator Driver"); MODULE_AUTHOR("Fred Richter <frichter@hauppauge.com>"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/lgdt3306a.h b/drivers/media/dvb-frontends/lgdt3306a.h index 9dbb2dc..6ce337e 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.h +++ b/drivers/media/dvb-frontends/lgdt3306a.h @@ -56,6 +56,10 @@ struct lgdt3306a_config { /* demod clock freq in MHz; 24 or 25 supported */ int xtalMHz; + + /* returned by driver if using i2c bus multiplexing */ + struct dvb_frontend **fe; + struct i2c_adapter **i2c_adapter; }; #if IS_REACHABLE(CONFIG_DVB_LGDT3306A) -- 2.9.3 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 1/2] [media] lgdt3306a: support i2c mux for use by em28xx 2016-12-18 2:55 [PATCH v2 1/2] [media] lgdt3306a: support i2c mux for use by em28xx Kevin Cheng @ 2017-01-09 11:46 ` Hans Verkuil 2017-01-10 3:14 ` [PATCH v3 0/2] Support for Hauppauge WinTV-dualHD 01595 ATSC/QAM Kevin Cheng ` (2 more replies) 0 siblings, 3 replies; 5+ messages in thread From: Hans Verkuil @ 2017-01-09 11:46 UTC (permalink / raw) To: Kevin Cheng, linux-media On 12/18/2016 03:55 AM, Kevin Cheng wrote: > Adds an i2c mux to the lgdt3306a demodulator. This was done to support > the Hauppauge WinTV-dualHD 01595 USB TV tuner (em28xx), which utilizes two > si2157 tuners behind gate control. > > Signed-off-by: Kevin Cheng <kcheng@gmail.com> > --- > drivers/media/dvb-frontends/Kconfig | 2 +- > drivers/media/dvb-frontends/lgdt3306a.c | 108 ++++++++++++++++++++++++++++++++ > drivers/media/dvb-frontends/lgdt3306a.h | 4 ++ > 3 files changed, 113 insertions(+), 1 deletion(-) > > diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig > index c841fa1..16f9afa 100644 > --- a/drivers/media/dvb-frontends/Kconfig > +++ b/drivers/media/dvb-frontends/Kconfig > @@ -619,7 +619,7 @@ config DVB_LGDT3305 > > config DVB_LGDT3306A > tristate "LG Electronics LGDT3306A based" > - depends on DVB_CORE && I2C > + depends on DVB_CORE && I2C && I2C_MUX > default m if !MEDIA_SUBDRV_AUTOSELECT > help > An ATSC 8VSB and QAM-B 64/256 demodulator module. Say Y when you want > diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c > index 19dca46..b191e01 100644 > --- a/drivers/media/dvb-frontends/lgdt3306a.c > +++ b/drivers/media/dvb-frontends/lgdt3306a.c > @@ -22,6 +22,7 @@ > #include <linux/dvb/frontend.h> > #include "dvb_math.h" > #include "lgdt3306a.h" > +#include <linux/i2c-mux.h> > > > static int debug; > @@ -65,6 +66,8 @@ struct lgdt3306a_state { > enum fe_modulation current_modulation; > u32 current_frequency; > u32 snr; > + > + struct i2c_mux_core *muxc; > }; > > /* > @@ -2131,6 +2134,111 @@ static const struct dvb_frontend_ops lgdt3306a_ops = { > .search = lgdt3306a_search, > }; > > +static int lgdt3306a_select(struct i2c_mux_core *muxc, u32 chan) > +{ > + struct i2c_client *client = i2c_mux_priv(muxc); > + struct lgdt3306a_state *state = i2c_get_clientdata(client); > + > + return lgdt3306a_i2c_gate_ctrl(&state->frontend, 1); > +} > + > +static int lgdt3306a_deselect(struct i2c_mux_core *muxc, u32 chan) > +{ > + struct i2c_client *client = i2c_mux_priv(muxc); > + struct lgdt3306a_state *state = i2c_get_clientdata(client); > + > + return lgdt3306a_i2c_gate_ctrl(&state->frontend, 0); > +} > + > +static int lgdt3306a_probe(struct i2c_client *client, > + const struct i2c_device_id *id) > +{ > + struct lgdt3306a_config *config = client->dev.platform_data; You assign config here... > + struct lgdt3306a_state *state; > + struct dvb_frontend *fe; > + int ret; > + > + config = kzalloc(sizeof(struct lgdt3306a_config), GFP_KERNEL); ...and then overwrite it here. Don't assign config the first time, it's confusing. > + if (config == NULL) { > + ret = -ENOMEM; > + goto fail; > + } > + > + memcpy(config, client->dev.platform_data, > + sizeof(struct lgdt3306a_config)); > + > + config->i2c_addr = client->addr; > + fe = lgdt3306a_attach(config, client->adapter); > + if (fe == NULL) { > + ret = -ENODEV; > + goto err_fe; > + } > + > + i2c_set_clientdata(client, fe->demodulator_priv); > + state = fe->demodulator_priv; > + > + /* create mux i2c adapter for tuner */ > + state->muxc = i2c_mux_alloc(client->adapter, &client->dev, > + 1, 0, I2C_MUX_LOCKED, > + lgdt3306a_select, lgdt3306a_deselect); > + if (!state->muxc) { > + ret = -ENOMEM; > + goto err_kfree; > + } > + state->muxc->priv = client; > + ret = i2c_mux_add_adapter(state->muxc, 0, 0, 0); > + if (ret) > + goto err_kfree; > + > + /* create dvb_frontend */ > + fe->ops.i2c_gate_ctrl = NULL; > + *config->i2c_adapter = state->muxc->adapter[0]; > + *config->fe = fe; > + > + return 0; > + > +err_kfree: > + kfree(state); > +err_fe: > + kfree(config); > +fail: > + dev_dbg(&client->dev, "failed=%d\n", ret); > + return ret; > +} > + > +static int lgdt3306a_remove(struct i2c_client *client) > +{ > + struct lgdt3306a_state *state = i2c_get_clientdata(client); > + > + i2c_mux_del_adapters(state->muxc); > + > + state->frontend.ops.release = NULL; > + state->frontend.demodulator_priv = NULL; > + > + kfree(state->cfg); > + kfree(state); > + > + return 0; > +} > + > +static const struct i2c_device_id lgdt3306a_id_table[] = { > + {"lgdt3306a", 0}, > + {} > +}; > +MODULE_DEVICE_TABLE(i2c, lgdt3306a_id_table); > + > +static struct i2c_driver lgdt3306a_driver = { > + .driver = { > + .name = "lgdt3306a", > + .suppress_bind_attrs = true, > + }, > + .probe = lgdt3306a_probe, > + .remove = lgdt3306a_remove, > + .id_table = lgdt3306a_id_table, > +}; > + > +module_i2c_driver(lgdt3306a_driver); > + > MODULE_DESCRIPTION("LG Electronics LGDT3306A ATSC/QAM-B Demodulator Driver"); > MODULE_AUTHOR("Fred Richter <frichter@hauppauge.com>"); > MODULE_LICENSE("GPL"); > diff --git a/drivers/media/dvb-frontends/lgdt3306a.h b/drivers/media/dvb-frontends/lgdt3306a.h > index 9dbb2dc..6ce337e 100644 > --- a/drivers/media/dvb-frontends/lgdt3306a.h > +++ b/drivers/media/dvb-frontends/lgdt3306a.h > @@ -56,6 +56,10 @@ struct lgdt3306a_config { > > /* demod clock freq in MHz; 24 or 25 supported */ > int xtalMHz; > + > + /* returned by driver if using i2c bus multiplexing */ > + struct dvb_frontend **fe; > + struct i2c_adapter **i2c_adapter; > }; > > #if IS_REACHABLE(CONFIG_DVB_LGDT3306A) > Regards, Hans ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v3 0/2] Support for Hauppauge WinTV-dualHD 01595 ATSC/QAM 2017-01-09 11:46 ` Hans Verkuil @ 2017-01-10 3:14 ` Kevin Cheng 2017-01-10 3:14 ` [PATCH v3 1/2] [media] lgdt3306a: support i2c mux for use by em28xx Kevin Cheng 2017-01-10 3:14 ` [PATCH v3 2/2] [media] em28xx: support for Hauppauge WinTV-dualHD 01595 ATSC/QAM Kevin Cheng 2 siblings, 0 replies; 5+ messages in thread From: Kevin Cheng @ 2017-01-10 3:14 UTC (permalink / raw) To: hverkuil, linux-media; +Cc: Linux Media Mailing List Adds support for the Hauppauge WinTV-dualHD TV tuner USB stick. Changes in response to review comments: * Removed extra struct initialization in lgdt3306a.c * Simplified initialization in em28xx-dvb.c Kevin Cheng (2): [media] lgdt3306a: support i2c mux for use by em28xx [media] em28xx: support for Hauppauge WinTV-dualHD 01595 ATSC/QAM drivers/media/dvb-frontends/Kconfig | 2 +- drivers/media/dvb-frontends/lgdt3306a.c | 108 ++++++++++++++++++++++++++++++++ drivers/media/dvb-frontends/lgdt3306a.h | 4 ++ drivers/media/usb/em28xx/em28xx-cards.c | 19 ++++++ drivers/media/usb/em28xx/em28xx-dvb.c | 78 +++++++++++++++++++++++ drivers/media/usb/em28xx/em28xx.h | 1 + 6 files changed, 211 insertions(+), 1 deletion(-) -- 2.9.3 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v3 1/2] [media] lgdt3306a: support i2c mux for use by em28xx 2017-01-09 11:46 ` Hans Verkuil 2017-01-10 3:14 ` [PATCH v3 0/2] Support for Hauppauge WinTV-dualHD 01595 ATSC/QAM Kevin Cheng @ 2017-01-10 3:14 ` Kevin Cheng 2017-01-10 3:14 ` [PATCH v3 2/2] [media] em28xx: support for Hauppauge WinTV-dualHD 01595 ATSC/QAM Kevin Cheng 2 siblings, 0 replies; 5+ messages in thread From: Kevin Cheng @ 2017-01-10 3:14 UTC (permalink / raw) To: hverkuil, linux-media; +Cc: Linux Media Mailing List Adds an i2c mux to the lgdt3306a demodulator. This was done to support the Hauppauge WinTV-dualHD 01595 USB TV tuner (em28xx), which utilizes two si2157 tuners behind gate control. Signed-off-by: Kevin Cheng <kcheng@gmail.com> --- drivers/media/dvb-frontends/Kconfig | 2 +- drivers/media/dvb-frontends/lgdt3306a.c | 108 ++++++++++++++++++++++++++++++++ drivers/media/dvb-frontends/lgdt3306a.h | 4 ++ 3 files changed, 113 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index c841fa1..16f9afa 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -619,7 +619,7 @@ config DVB_LGDT3305 config DVB_LGDT3306A tristate "LG Electronics LGDT3306A based" - depends on DVB_CORE && I2C + depends on DVB_CORE && I2C && I2C_MUX default m if !MEDIA_SUBDRV_AUTOSELECT help An ATSC 8VSB and QAM-B 64/256 demodulator module. Say Y when you want diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index 19dca46..c9b1eb3 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -22,6 +22,7 @@ #include <linux/dvb/frontend.h> #include "dvb_math.h" #include "lgdt3306a.h" +#include <linux/i2c-mux.h> static int debug; @@ -65,6 +66,8 @@ struct lgdt3306a_state { enum fe_modulation current_modulation; u32 current_frequency; u32 snr; + + struct i2c_mux_core *muxc; }; /* @@ -2131,6 +2134,111 @@ static const struct dvb_frontend_ops lgdt3306a_ops = { .search = lgdt3306a_search, }; +static int lgdt3306a_select(struct i2c_mux_core *muxc, u32 chan) +{ + struct i2c_client *client = i2c_mux_priv(muxc); + struct lgdt3306a_state *state = i2c_get_clientdata(client); + + return lgdt3306a_i2c_gate_ctrl(&state->frontend, 1); +} + +static int lgdt3306a_deselect(struct i2c_mux_core *muxc, u32 chan) +{ + struct i2c_client *client = i2c_mux_priv(muxc); + struct lgdt3306a_state *state = i2c_get_clientdata(client); + + return lgdt3306a_i2c_gate_ctrl(&state->frontend, 0); +} + +static int lgdt3306a_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct lgdt3306a_config *config; + struct lgdt3306a_state *state; + struct dvb_frontend *fe; + int ret; + + config = kzalloc(sizeof(struct lgdt3306a_config), GFP_KERNEL); + if (config == NULL) { + ret = -ENOMEM; + goto fail; + } + + memcpy(config, client->dev.platform_data, + sizeof(struct lgdt3306a_config)); + + config->i2c_addr = client->addr; + fe = lgdt3306a_attach(config, client->adapter); + if (fe == NULL) { + ret = -ENODEV; + goto err_fe; + } + + i2c_set_clientdata(client, fe->demodulator_priv); + state = fe->demodulator_priv; + + /* create mux i2c adapter for tuner */ + state->muxc = i2c_mux_alloc(client->adapter, &client->dev, + 1, 0, I2C_MUX_LOCKED, + lgdt3306a_select, lgdt3306a_deselect); + if (!state->muxc) { + ret = -ENOMEM; + goto err_kfree; + } + state->muxc->priv = client; + ret = i2c_mux_add_adapter(state->muxc, 0, 0, 0); + if (ret) + goto err_kfree; + + /* create dvb_frontend */ + fe->ops.i2c_gate_ctrl = NULL; + *config->i2c_adapter = state->muxc->adapter[0]; + *config->fe = fe; + + return 0; + +err_kfree: + kfree(state); +err_fe: + kfree(config); +fail: + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; +} + +static int lgdt3306a_remove(struct i2c_client *client) +{ + struct lgdt3306a_state *state = i2c_get_clientdata(client); + + i2c_mux_del_adapters(state->muxc); + + state->frontend.ops.release = NULL; + state->frontend.demodulator_priv = NULL; + + kfree(state->cfg); + kfree(state); + + return 0; +} + +static const struct i2c_device_id lgdt3306a_id_table[] = { + {"lgdt3306a", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, lgdt3306a_id_table); + +static struct i2c_driver lgdt3306a_driver = { + .driver = { + .name = "lgdt3306a", + .suppress_bind_attrs = true, + }, + .probe = lgdt3306a_probe, + .remove = lgdt3306a_remove, + .id_table = lgdt3306a_id_table, +}; + +module_i2c_driver(lgdt3306a_driver); + MODULE_DESCRIPTION("LG Electronics LGDT3306A ATSC/QAM-B Demodulator Driver"); MODULE_AUTHOR("Fred Richter <frichter@hauppauge.com>"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/lgdt3306a.h b/drivers/media/dvb-frontends/lgdt3306a.h index 9dbb2dc..6ce337e 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.h +++ b/drivers/media/dvb-frontends/lgdt3306a.h @@ -56,6 +56,10 @@ struct lgdt3306a_config { /* demod clock freq in MHz; 24 or 25 supported */ int xtalMHz; + + /* returned by driver if using i2c bus multiplexing */ + struct dvb_frontend **fe; + struct i2c_adapter **i2c_adapter; }; #if IS_REACHABLE(CONFIG_DVB_LGDT3306A) -- 2.9.3 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v3 2/2] [media] em28xx: support for Hauppauge WinTV-dualHD 01595 ATSC/QAM 2017-01-09 11:46 ` Hans Verkuil 2017-01-10 3:14 ` [PATCH v3 0/2] Support for Hauppauge WinTV-dualHD 01595 ATSC/QAM Kevin Cheng 2017-01-10 3:14 ` [PATCH v3 1/2] [media] lgdt3306a: support i2c mux for use by em28xx Kevin Cheng @ 2017-01-10 3:14 ` Kevin Cheng 2 siblings, 0 replies; 5+ messages in thread From: Kevin Cheng @ 2017-01-10 3:14 UTC (permalink / raw) To: hverkuil, linux-media; +Cc: Linux Media Mailing List Hauppauge WinTV-dualHD model 01595 is a USB 2.0 dual ATSC/QAM tuner with the following components: USB bridge: Empia em28274 Demodulator: 2x LG LGDT3306a at addresses 0xb2 and 0x1c Tuner: 2x Silicon Labs si2157 at addresses 0xc0 and 0xc4 This patch enables only the first tuner. Signed-off-by: Kevin Cheng <kcheng@gmail.com> --- drivers/media/usb/em28xx/em28xx-cards.c | 19 +++++++++ drivers/media/usb/em28xx/em28xx-dvb.c | 74 +++++++++++++++++++++++++++++++++ drivers/media/usb/em28xx/em28xx.h | 1 + 3 files changed, 94 insertions(+) diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 23c6749..5f90d08 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -509,6 +509,7 @@ static struct em28xx_reg_seq plex_px_bcud[] = { /* * 2040:0265 Hauppauge WinTV-dualHD DVB + * 2040:026d Hauppauge WinTV-dualHD ATSC/QAM * reg 0x80/0x84: * GPIO_0: Yellow LED tuner 1, 0=on, 1=off * GPIO_1: Green LED tuner 1, 0=on, 1=off @@ -2389,6 +2390,21 @@ struct em28xx_board em28xx_boards[] = { .ir_codes = RC_MAP_HAUPPAUGE, .leds = hauppauge_dualhd_leds, }, + /* + * 2040:026d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM). + * Empia EM28274, 2x LG LGDT3306A, 2x Silicon Labs Si2157 + */ + [EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595] = { + .name = "Hauppauge WinTV-dualHD 01595 ATSC/QAM", + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, + .tuner_type = TUNER_ABSENT, + .tuner_gpio = hauppauge_dualhd_dvb, + .has_dvb = 1, + .ir_codes = RC_MAP_HAUPPAUGE, + .leds = hauppauge_dualhd_leds, + }, }; EXPORT_SYMBOL_GPL(em28xx_boards); @@ -2514,6 +2530,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 }, { USB_DEVICE(0x2040, 0x0265), .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, + { USB_DEVICE(0x2040, 0x026d), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, { USB_DEVICE(0x0438, 0xb002), .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 }, { USB_DEVICE(0x2001, 0xf112), @@ -2945,6 +2963,7 @@ static void em28xx_card_setup(struct em28xx *dev) case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C: case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB: + case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595: { struct tveeprom tv; diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 75a75da..82edd37 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -37,6 +37,7 @@ #include "lgdt330x.h" #include "lgdt3305.h" +#include "lgdt3306a.h" #include "zl10353.h" #include "s5h1409.h" #include "mt2060.h" @@ -920,6 +921,17 @@ static struct tda18271_config pinnacle_80e_dvb_config = { .role = TDA18271_MASTER, }; +static struct lgdt3306a_config hauppauge_01595_lgdt3306a_config = { + .qam_if_khz = 4000, + .vsb_if_khz = 3250, + .spectral_inversion = 0, + .deny_i2c_rptr = 0, + .mpeg_mode = LGDT3306A_MPEG_SERIAL, + .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE, + .tpvalid_polarity = LGDT3306A_TP_VALID_HIGH, + .xtalMHz = 25, +}; + /* ------------------------------------------------------------------ */ static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) @@ -1950,6 +1962,68 @@ static int em28xx_dvb_init(struct em28xx *dev) } break; + case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595: + { + struct i2c_adapter *adapter; + struct i2c_client *client; + struct i2c_board_info info = {}; + struct lgdt3306a_config lgdt3306a_config; + struct si2157_config si2157_config = {}; + + /* attach demod */ + lgdt3306a_config = hauppauge_01595_lgdt3306a_config; + lgdt3306a_config.fe = &dvb->fe[0]; + lgdt3306a_config.i2c_adapter = &adapter; + strlcpy(info.type, "lgdt3306a", sizeof(info.type)); + info.addr = 0x59; + info.platform_data = &lgdt3306a_config; + request_module(info.type); + client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], + &info); + if (client == NULL || client->dev.driver == NULL) { + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + result = -ENODEV; + goto out_free; + } + + dvb->i2c_client_demod = client; + + /* attach tuner */ + si2157_config.fe = dvb->fe[0]; + si2157_config.if_port = 1; + si2157_config.inversion = 1; +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + si2157_config.mdev = dev->media_dev; +#endif + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", sizeof(info.type)); + info.addr = 0x60; + info.platform_data = &si2157_config; + request_module(info.type); + + client = i2c_new_device(adapter, &info); + if (client == NULL || client->dev.driver == NULL) { + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + + dvb->i2c_client_tuner = client; + } + break; default: dev_err(&dev->intf->dev, "The frontend of your DVB/ATSC card isn't supported yet\n"); diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index ca59e2d..e9f3799 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -147,6 +147,7 @@ #define EM2884_BOARD_ELGATO_EYETV_HYBRID_2008 97 #define EM28178_BOARD_PLEX_PX_BCUD 98 #define EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB 99 +#define EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 100 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 -- 2.9.3 ^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2017-01-10 3:14 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2016-12-18 2:55 [PATCH v2 1/2] [media] lgdt3306a: support i2c mux for use by em28xx Kevin Cheng 2017-01-09 11:46 ` Hans Verkuil 2017-01-10 3:14 ` [PATCH v3 0/2] Support for Hauppauge WinTV-dualHD 01595 ATSC/QAM Kevin Cheng 2017-01-10 3:14 ` [PATCH v3 1/2] [media] lgdt3306a: support i2c mux for use by em28xx Kevin Cheng 2017-01-10 3:14 ` [PATCH v3 2/2] [media] em28xx: support for Hauppauge WinTV-dualHD 01595 ATSC/QAM Kevin Cheng
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox