aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/acpi_pad.c37
-rw-r--r--drivers/acpi/ec.c126
-rw-r--r--drivers/acpi/processor_idle.c64
-rw-r--r--drivers/acpi/sbshc.c2
-rw-r--r--drivers/acpi/video.c43
-rw-r--r--drivers/base/memory.c34
-rw-r--r--drivers/char/Kconfig2
-rw-r--r--drivers/char/agp/amd64-agp.c5
-rw-r--r--drivers/char/agp/intel-agp.c6
-rw-r--r--drivers/char/hw_random/virtio-rng.c6
-rw-r--r--drivers/edac/amd64_edac.c2
-rw-r--r--drivers/edac/i5000_edac.c8
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c4
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c6
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h3
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c53
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c68
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h2
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c35
-rw-r--r--drivers/gpu/drm/i915/intel_bios.h40
-rw-r--r--drivers/gpu/drm/i915/intel_display.c84
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c75
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c50
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c17
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c83
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c2
-rw-r--r--drivers/i2c/busses/i2c-ali1563.c8
-rw-r--r--drivers/i2c/busses/i2c-pca-isa.c4
-rw-r--r--drivers/i2c/busses/i2c-pca-platform.c4
-rw-r--r--drivers/i2c/busses/i2c-piix4.c4
-rw-r--r--drivers/i2c/busses/i2c-viapro.c4
-rw-r--r--drivers/i2c/i2c-core.c7
-rw-r--r--drivers/input/evdev.c3
-rw-r--r--drivers/input/input.c86
-rw-r--r--drivers/input/joystick/gf2k.c2
-rw-r--r--drivers/input/joystick/xpad.c4
-rw-r--r--drivers/input/keyboard/atkbd.c69
-rw-r--r--drivers/input/keyboard/davinci_keyscan.c8
-rw-r--r--drivers/input/mouse/bcm5974.c44
-rw-r--r--drivers/input/mouse/psmouse-base.c69
-rw-r--r--drivers/input/mouse/sentelic.c6
-rw-r--r--drivers/input/mouse/synaptics.c10
-rw-r--r--drivers/input/mouse/synaptics.h1
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h7
-rw-r--r--drivers/macintosh/smu.c2
-rw-r--r--drivers/macintosh/therm_pm72.c2
-rw-r--r--drivers/macintosh/therm_windtunnel.c2
-rw-r--r--drivers/media/IR/ir-keytable.c2
-rw-r--r--drivers/media/common/tuners/tda8290.c12
-rw-r--r--drivers/media/dvb/Kconfig4
-rw-r--r--drivers/media/dvb/Makefile14
-rw-r--r--drivers/media/dvb/frontends/Kconfig19
-rw-r--r--drivers/media/dvb/frontends/Makefile2
-rw-r--r--drivers/media/dvb/frontends/dib8000.h2
-rw-r--r--drivers/media/dvb/frontends/lgdt3305.h6
-rw-r--r--drivers/media/dvb/frontends/mb86a16.c1878
-rw-r--r--drivers/media/dvb/frontends/mb86a16.h52
-rw-r--r--drivers/media/dvb/frontends/mb86a16_priv.h151
-rw-r--r--drivers/media/dvb/frontends/tda10021.c4
-rw-r--r--drivers/media/dvb/frontends/tda665x.c257
-rw-r--r--drivers/media/dvb/frontends/tda665x.h52
-rw-r--r--drivers/media/dvb/mantis/Kconfig32
-rw-r--r--drivers/media/dvb/mantis/Makefile28
-rw-r--r--drivers/media/dvb/mantis/hopper_cards.c275
-rw-r--r--drivers/media/dvb/mantis/hopper_vp3028.c88
-rw-r--r--drivers/media/dvb/mantis/hopper_vp3028.h30
-rw-r--r--drivers/media/dvb/mantis/mantis_ca.c207
-rw-r--r--drivers/media/dvb/mantis/mantis_ca.h27
-rw-r--r--drivers/media/dvb/mantis/mantis_cards.c305
-rw-r--r--drivers/media/dvb/mantis/mantis_common.h179
-rw-r--r--drivers/media/dvb/mantis/mantis_core.c238
-rw-r--r--drivers/media/dvb/mantis/mantis_core.h57
-rw-r--r--drivers/media/dvb/mantis/mantis_dma.c256
-rw-r--r--drivers/media/dvb/mantis/mantis_dma.h30
-rw-r--r--drivers/media/dvb/mantis/mantis_dvb.c296
-rw-r--r--drivers/media/dvb/mantis/mantis_dvb.h35
-rw-r--r--drivers/media/dvb/mantis/mantis_evm.c117
-rw-r--r--drivers/media/dvb/mantis/mantis_hif.c240
-rw-r--r--drivers/media/dvb/mantis/mantis_hif.h29
-rw-r--r--drivers/media/dvb/mantis/mantis_i2c.c267
-rw-r--r--drivers/media/dvb/mantis/mantis_i2c.h30
-rw-r--r--drivers/media/dvb/mantis/mantis_input.c148
-rw-r--r--drivers/media/dvb/mantis/mantis_ioc.c130
-rw-r--r--drivers/media/dvb/mantis/mantis_ioc.h51
-rw-r--r--drivers/media/dvb/mantis/mantis_link.h83
-rw-r--r--drivers/media/dvb/mantis/mantis_pci.c177
-rw-r--r--drivers/media/dvb/mantis/mantis_pci.h27
-rw-r--r--drivers/media/dvb/mantis/mantis_pcmcia.c120
-rw-r--r--drivers/media/dvb/mantis/mantis_reg.h197
-rw-r--r--drivers/media/dvb/mantis/mantis_uart.c186
-rw-r--r--drivers/media/dvb/mantis/mantis_uart.h58
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1033.c212
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1033.h30
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1034.c119
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1034.h33
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1041.c358
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1041.h33
-rw-r--r--drivers/media/dvb/mantis/mantis_vp2033.c187
-rw-r--r--drivers/media/dvb/mantis/mantis_vp2033.h30
-rw-r--r--drivers/media/dvb/mantis/mantis_vp2040.c186
-rw-r--r--drivers/media/dvb/mantis/mantis_vp2040.h32
-rw-r--r--drivers/media/dvb/mantis/mantis_vp3028.c38
-rw-r--r--drivers/media/dvb/mantis/mantis_vp3028.h33
-rw-r--r--drivers/media/dvb/mantis/mantis_vp3030.c105
-rw-r--r--drivers/media/dvb/mantis/mantis_vp3030.h30
-rw-r--r--drivers/media/video/gspca/gspca.c2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k4aa.c6
-rw-r--r--drivers/media/video/gspca/ov534.c2
-rw-r--r--drivers/media/video/gspca/sn9c20x.c2
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h1
-rw-r--r--drivers/media/video/gspca/sunplus.c26
-rw-r--r--drivers/media/video/gspca/vc032x.c4
-rw-r--r--drivers/media/video/mx1_camera.c2
-rw-r--r--drivers/media/video/rj54n1cb0c.c2
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c13
-rw-r--r--drivers/media/video/saa7134/saa7134-ts.c13
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c2
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c2
-rw-r--r--drivers/media/video/uvc/uvc_queue.c13
-rw-r--r--drivers/media/video/uvc/uvc_video.c45
-rw-r--r--drivers/media/video/uvc/uvcvideo.h5
-rw-r--r--drivers/mfd/Makefile6
-rw-r--r--drivers/mfd/asic3.c40
-rw-r--r--drivers/mfd/mc13783-core.c4
-rw-r--r--drivers/mfd/t7l66xb.c55
-rw-r--r--drivers/mfd/tc6387xb.c119
-rw-r--r--drivers/mfd/tc6393xb.c56
-rw-r--r--drivers/mfd/tmio_core.c52
-rw-r--r--drivers/mfd/wm8350-core.c3
-rw-r--r--drivers/mfd/wm8350-irq.c4
-rw-r--r--drivers/mmc/host/tmio_mmc.c59
-rw-r--r--drivers/mmc/host/tmio_mmc.h46
-rw-r--r--drivers/serial/8250_pnp.c2
-rw-r--r--drivers/serial/pmac_zilog.c11
-rw-r--r--drivers/serial/sh-sci.c13
-rw-r--r--drivers/staging/cx25821/cx25821-medusa-video.c4
-rw-r--r--drivers/video/s3c-fb.c14
-rw-r--r--drivers/video/via/accel.c5
-rw-r--r--drivers/video/via/viafbdev.c11
-rw-r--r--drivers/virtio/virtio_balloon.c6
-rw-r--r--drivers/watchdog/iTCO_wdt.c45
141 files changed, 9016 insertions, 706 deletions
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index 97991ac6f5f..7e52295f1ec 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -208,7 +208,7 @@ static int power_saving_thread(void *data)
* the mechanism only works when all CPUs have RT task running,
* as if one CPU hasn't RT task, RT task from other CPUs will
* borrow CPU time from this CPU and cause RT task use > 95%
- * CPU time. To make 'avoid staration' work, takes a nap here.
+ * CPU time. To make 'avoid starvation' work, takes a nap here.
*/
if (do_sleep)
schedule_timeout_killable(HZ * idle_pct / 100);
@@ -222,14 +222,18 @@ static struct task_struct *ps_tsks[NR_CPUS];
static unsigned int ps_tsk_num;
static int create_power_saving_task(void)
{
+ int rc = -ENOMEM;
+
ps_tsks[ps_tsk_num] = kthread_run(power_saving_thread,
(void *)(unsigned long)ps_tsk_num,
"power_saving/%d", ps_tsk_num);
- if (ps_tsks[ps_tsk_num]) {
+ rc = IS_ERR(ps_tsks[ps_tsk_num]) ? PTR_ERR(ps_tsks[ps_tsk_num]) : 0;
+ if (!rc)
ps_tsk_num++;
- return 0;
- }
- return -EINVAL;
+ else
+ ps_tsks[ps_tsk_num] = NULL;
+
+ return rc;
}
static void destroy_power_saving_task(void)
@@ -237,6 +241,7 @@ static void destroy_power_saving_task(void)
if (ps_tsk_num > 0) {
ps_tsk_num--;
kthread_stop(ps_tsks[ps_tsk_num]);
+ ps_tsks[ps_tsk_num] = NULL;
}
}
@@ -253,7 +258,7 @@ static void set_power_saving_task_num(unsigned int num)
}
}
-static int acpi_pad_idle_cpus(unsigned int num_cpus)
+static void acpi_pad_idle_cpus(unsigned int num_cpus)
{
get_online_cpus();
@@ -261,7 +266,6 @@ static int acpi_pad_idle_cpus(unsigned int num_cpus)
set_power_saving_task_num(num_cpus);
put_online_cpus();
- return 0;
}
static uint32_t acpi_pad_idle_cpus_num(void)
@@ -369,19 +373,21 @@ static void acpi_pad_remove_sysfs(struct acpi_device *device)
static int acpi_pad_pur(acpi_handle handle, int *num_cpus)
{
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
- acpi_status status;
union acpi_object *package;
int rev, num, ret = -EINVAL;
- status = acpi_evaluate_object(handle, "_PUR", NULL, &buffer);
- if (ACPI_FAILURE(status))
+ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_PUR", NULL, &buffer)))
+ return -EINVAL;
+
+ if (!buffer.length || !buffer.pointer)
return -EINVAL;
+
package = buffer.pointer;
if (package->type != ACPI_TYPE_PACKAGE || package->package.count != 2)
goto out;
rev = package->package.elements[0].integer.value;
num = package->package.elements[1].integer.value;
- if (rev != 1)
+ if (rev != 1 || num < 0)
goto out;
*num_cpus = num;
ret = 0;
@@ -410,7 +416,7 @@ static void acpi_pad_ost(acpi_handle handle, int stat,
static void acpi_pad_handle_notify(acpi_handle handle)
{
- int num_cpus, ret;
+ int num_cpus;
uint32_t idle_cpus;
mutex_lock(&isolated_cpus_lock);
@@ -418,12 +424,9 @@ static void acpi_pad_handle_notify(acpi_handle handle)
mutex_unlock(&isolated_cpus_lock);
return;
}
- ret = acpi_pad_idle_cpus(num_cpus);
+ acpi_pad_idle_cpus(num_cpus);
idle_cpus = acpi_pad_idle_cpus_num();
- if (!ret)
- acpi_pad_ost(handle, 0, idle_cpus);
- else
- acpi_pad_ost(handle, 1, 0);
+ acpi_pad_ost(handle, 0, idle_cpus);
mutex_unlock(&isolated_cpus_lock);
}
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index fd1801bdee6..d6471bb6852 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -201,14 +201,13 @@ unlock:
spin_unlock_irqrestore(&ec->curr_lock, flags);
}
-static void acpi_ec_gpe_query(void *ec_cxt);
+static int acpi_ec_sync_query(struct acpi_ec *ec);
-static int ec_check_sci(struct acpi_ec *ec, u8 state)
+static int ec_check_sci_sync(struct acpi_ec *ec, u8 state)
{
if (state & ACPI_EC_FLAG_SCI) {
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
- return acpi_os_execute(OSL_EC_BURST_HANDLER,
- acpi_ec_gpe_query, ec);
+ return acpi_ec_sync_query(ec);
}
return 0;
}
@@ -249,11 +248,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
{
unsigned long tmp;
int ret = 0;
- pr_debug(PREFIX "transaction start\n");
- /* disable GPE during transaction if storm is detected */
- if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
- acpi_disable_gpe(NULL, ec->gpe);
- }
if (EC_FLAGS_MSI)
udelay(ACPI_EC_MSI_UDELAY);
/* start transaction */
@@ -265,20 +259,9 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
spin_unlock_irqrestore(&ec->curr_lock, tmp);
ret = ec_poll(ec);
- pr_debug(PREFIX "transaction end\n");
spin_lock_irqsave(&ec->curr_lock, tmp);
ec->curr = NULL;
spin_unlock_irqrestore(&ec->curr_lock, tmp);
- if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
- /* check if we received SCI during transaction */
- ec_check_sci(ec, acpi_ec_read_status(ec));
- /* it is safe to enable GPE outside of transaction */
- acpi_enable_gpe(NULL, ec->gpe);
- } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) {
- pr_info(PREFIX "GPE storm detected, "
- "transactions will use polling mode\n");
- set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
- }
return ret;
}
@@ -321,7 +304,26 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
status = -ETIME;
goto end;
}
+ pr_debug(PREFIX "transaction start\n");
+ /* disable GPE during transaction if storm is detected */
+ if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
+ acpi_disable_gpe(NULL, ec->gpe);
+ }
+
status = acpi_ec_transaction_unlocked(ec, t);
+
+ /* check if we received SCI during transaction */
+ ec_check_sci_sync(ec, acpi_ec_read_status(ec));
+ if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
+ msleep(1);
+ /* it is safe to enable GPE outside of transaction */
+ acpi_enable_gpe(NULL, ec->gpe);
+ } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) {
+ pr_info(PREFIX "GPE storm detected, "
+ "transactions will use polling mode\n");
+ set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
+ }
+ pr_debug(PREFIX "transaction end\n");
end:
if (ec->global_lock)
acpi_release_global_lock(glk);
@@ -443,7 +445,7 @@ int ec_transaction(u8 command,
EXPORT_SYMBOL(ec_transaction);
-static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
+static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data)
{
int result;
u8 d;
@@ -452,20 +454,16 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
.wlen = 0, .rlen = 1};
if (!ec || !data)
return -EINVAL;
-
/*
* Query the EC to find out which _Qxx method we need to evaluate.
* Note that successful completion of the query causes the ACPI_EC_SCI
* bit to be cleared (and thus clearing the interrupt source).
*/
-
- result = acpi_ec_transaction(ec, &t);
+ result = acpi_ec_transaction_unlocked(ec, &t);
if (result)
return result;
-
if (!d)
return -ENODATA;
-
*data = d;
return 0;
}
@@ -509,43 +507,79 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
-static void acpi_ec_gpe_query(void *ec_cxt)
+static void acpi_ec_run(void *cxt)
{
- struct acpi_ec *ec = ec_cxt;
- u8 value = 0;
- struct acpi_ec_query_handler *handler, copy;
-
- if (!ec || acpi_ec_query(ec, &value))
+ struct acpi_ec_query_handler *handler = cxt;
+ if (!handler)
return;
- mutex_lock(&ec->lock);
+ pr_debug(PREFIX "start query execution\n");
+ if (handler->func)
+ handler->func(handler->data);
+ else if (handler->handle)
+ acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
+ pr_debug(PREFIX "stop query execution\n");
+ kfree(handler);
+}
+
+static int acpi_ec_sync_query(struct acpi_ec *ec)
+{
+ u8 value = 0;
+ int status;
+ struct acpi_ec_query_handler *handler, *copy;
+ if ((status = acpi_ec_query_unlocked(ec, &value)))
+ return status;
list_for_each_entry(handler, &ec->list, node) {
if (value == handler->query_bit) {
/* have custom handler for this bit */
- memcpy(&copy, handler, sizeof(copy));
- mutex_unlock(&ec->lock);
- if (copy.func) {
- copy.func(copy.data);
- } else if (copy.handle) {
- acpi_evaluate_object(copy.handle, NULL, NULL, NULL);
- }
- return;
+ copy = kmalloc(sizeof(*handler), GFP_KERNEL);
+ if (!copy)
+ return -ENOMEM;
+ memcpy(copy, handler, sizeof(*copy));
+ pr_debug(PREFIX "push query execution (0x%2x) on queue\n", value);
+ return acpi_os_execute((copy->func) ?
+ OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER,
+ acpi_ec_run, copy);
}
}
+ return 0;
+}
+
+static void acpi_ec_gpe_query(void *ec_cxt)
+{
+ struct acpi_ec *ec = ec_cxt;
+ if (!ec)
+ return;
+ mutex_lock(&ec->lock);
+ acpi_ec_sync_query(ec);
mutex_unlock(&ec->lock);
}
+static void acpi_ec_gpe_query(void *ec_cxt);
+
+static int ec_check_sci(struct acpi_ec *ec, u8 state)
+{
+ if (state & ACPI_EC_FLAG_SCI) {
+ if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
+ pr_debug(PREFIX "push gpe query to the queue\n");
+ return acpi_os_execute(OSL_NOTIFY_HANDLER,
+ acpi_ec_gpe_query, ec);
+ }
+ }
+ return 0;
+}
+
static u32 acpi_ec_gpe_handler(void *data)
{
struct acpi_ec *ec = data;
- u8 status;
pr_debug(PREFIX "~~~> interrupt\n");
- status = acpi_ec_read_status(ec);
- advance_transaction(ec, status);
- if (ec_transaction_done(ec) && (status & ACPI_EC_FLAG_IBF) == 0)
+ advance_transaction(ec, acpi_ec_read_status(ec));
+ if (ec_transaction_done(ec) &&
+ (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) {
wake_up(&ec->wait);
- ec_check_sci(ec, status);
+ ec_check_sci(ec, acpi_ec_read_status(ec));
+ }
return ACPI_INTERRUPT_HANDLED;
}
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index d1676b1754d..7c0441f63b3 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -305,6 +305,28 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
pr->power.states[ACPI_STATE_C2].latency = acpi_gbl_FADT.C2latency;
pr->power.states[ACPI_STATE_C3].latency = acpi_gbl_FADT.C3latency;
+ /*
+ * FADT specified C2 latency must be less than or equal to
+ * 100 microseconds.
+ */
+ if (acpi_gbl_FADT.C2latency > ACPI_PROCESSOR_MAX_C2_LATENCY) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "C2 latency too large [%d]\n", acpi_gbl_FADT.C2latency));
+ /* invalidate C2 */
+ pr->power.states[ACPI_STATE_C2].address = 0;
+ }
+
+ /*
+ * FADT supplied C3 latency must be less than or equal to
+ * 1000 microseconds.
+ */
+ if (acpi_gbl_FADT.C3latency > ACPI_PROCESSOR_MAX_C3_LATENCY) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "C3 latency too large [%d]\n", acpi_gbl_FADT.C3latency));
+ /* invalidate C3 */
+ pr->power.states[ACPI_STATE_C3].address = 0;
+ }
+
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"lvl2[0x%08x] lvl3[0x%08x]\n",
pr->power.states[ACPI_STATE_C2].address,
@@ -494,33 +516,6 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
return status;
}
-static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx)
-{
-
- if (!cx->address)
- return;
-
- /*
- * C2 latency must be less than or equal to 100
- * microseconds.
- */
- else if (cx->latency > ACPI_PROCESSOR_MAX_C2_LATENCY) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "latency too large [%d]\n", cx->latency));
- return;
- }
-
- /*
- * Otherwise we've met all of our C2 requirements.
- * Normalize the C2 latency to expidite policy
- */
- cx->valid = 1;
-
- cx->latency_ticks = cx->latency;
-
- return;
-}
-
static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
struct acpi_processor_cx *cx)
{
@@ -532,16 +527,6 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
return;
/*
- * C3 latency must be less than or equal to 1000
- * microseconds.
- */
- else if (cx->latency > ACPI_PROCESSOR_MAX_C3_LATENCY) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "latency too large [%d]\n", cx->latency));
- return;
- }
-
- /*
* PIIX4 Erratum #18: We don't support C3 when Type-F (fast)
* DMA transfers are used by any ISA device to avoid livelock.
* Note that we could disable Type-F DMA (as recommended by
@@ -629,7 +614,10 @@ static int acpi_processor_power_verify(struct acpi_processor *pr)
break;
case ACPI_STATE_C2:
- acpi_processor_power_verify_c2(cx);
+ if (!cx->address)
+ break;
+ cx->valid = 1;
+ cx->latency_ticks = cx->latency; /* Normalize latency */
break;
case ACPI_STATE_C3:
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
index d9339806df4..fd09229282e 100644
--- a/drivers/acpi/sbshc.c
+++ b/drivers/acpi/sbshc.c
@@ -242,7 +242,7 @@ static int smbus_alarm(void *context)
case ACPI_SBS_CHARGER:
case ACPI_SBS_MANAGER:
case ACPI_SBS_BATTERY:
- acpi_os_execute(OSL_GPE_HANDLER,
+ acpi_os_execute(OSL_NOTIFY_HANDLER,
acpi_smbus_callback, hc);
default:;
}
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 72e76b4b653..b765790b32b 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -78,6 +78,13 @@ MODULE_LICENSE("GPL");
static int brightness_switch_enabled = 1;
module_param(brightness_switch_enabled, bool, 0644);
+/*
+ * By default, we don't allow duplicate ACPI video bus devices
+ * under the same VGA controller
+ */
+static int allow_duplicates;
+module_param(allow_duplicates, bool, 0644);
+
static int register_count = 0;
static int acpi_video_bus_add(struct acpi_device *device);
static int acpi_video_bus_remove(struct acpi_device *device, int type);
@@ -2239,11 +2246,47 @@ static int acpi_video_resume(struct acpi_device *device)
return AE_OK;
}
+static acpi_status
+acpi_video_bus_match(acpi_handle handle, u32 level, void *context,
+ void **return_value)
+{
+ struct acpi_device *device = context;
+ struct acpi_device *sibling;
+ int result;
+
+ if (handle == device->handle)
+ return AE_CTRL_TERMINATE;
+
+ result = acpi_bus_get_device(handle, &sibling);
+ if (result)
+ return AE_OK;
+
+ if (!strcmp(acpi_device_name(sibling), ACPI_VIDEO_BUS_NAME))
+ return AE_ALREADY_EXISTS;
+
+ return AE_OK;
+}
+
static int acpi_video_bus_add(struct acpi_device *device)
{
struct acpi_video_bus *video;
struct input_dev *input;
int error;
+ acpi_status status;
+
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
+ device->parent->handle, 1,
+ acpi_video_bus_match, NULL,
+ device, NULL);
+ if (status == AE_ALREADY_EXISTS) {
+ printk(KERN_WARNING FW_BUG
+ "Duplicate ACPI video bus devices for the"
+ " same VGA controller, please try module "
+ "parameter \"video.allow_duplicates=1\""
+ "if the current driver doesn't work.\n");
+ if (!allow_duplicates)
+ return -ENODEV;
+ }
video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
if (!video)
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index d7d77d4a402..ae6b6c43cff 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -309,17 +309,19 @@ static SYSDEV_ATTR(removable, 0444, show_mem_removable, NULL);
* Block size attribute stuff
*/
static ssize_t
-print_block_size(struct class *class, char *buf)
+print_block_size(struct sysdev_class *class,
+ struct sysdev_class_attribute *class_attr,
+ char *buf)
{
- return sprintf(buf, "%lx\n", (unsigned long)PAGES_PER_SECTION * PAGE_SIZE);
+ return sprintf(buf, "%#lx\n", (unsigned long)PAGES_PER_SECTION * PAGE_SIZE);
}
-static CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL);
+static SYSDEV_CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL);
static int block_size_init(void)
{
return sysfs_create_file(&memory_sysdev_class.kset.kobj,
- &class_attr_block_size_bytes.attr);
+ &attr_block_size_bytes.attr);
}
/*
@@ -330,7 +332,9 @@ static int block_size_init(void)
*/
#ifdef CONFIG_ARCH_MEMORY_PROBE
static ssize_t
-memory_probe_store(struct class *class, const char *buf, size_t count)
+memory_probe_store(struct sysdev_class *class,
+ struct sysdev_class_attribute *class_attr,
+ const char *buf, size_t count)
{
u64 phys_addr;
int nid;
@@ -346,12 +350,12 @@ memory_probe_store(struct class *class, const char *buf, size_t count)
return count;
}
-static CLASS_ATTR(probe, S_IWUSR, NULL, memory_probe_store);
+static SYSDEV_CLASS_ATTR(probe, S_IWUSR, NULL, memory_probe_store);
static int memory_probe_init(void)
{
return sysfs_create_file(&memory_sysdev_class.kset.kobj,
- &class_attr_probe.attr);
+ &attr_probe.attr);
}
#else
static inline int memory_probe_init(void)
@@ -367,7 +371,9 @@ static inline int memory_probe_init(void)
/* Soft offline a page */
static ssize_t
-store_soft_offline_page(struct class *class, const char *buf, size_t count)
+store_soft_offline_page(struct sysdev_class *class,
+ struct sysdev_class_attribute *class_attr,
+ const char *buf, size_t count)
{
int ret;
u64 pfn;
@@ -384,7 +390,9 @@ store_soft_offline_page(struct class *class, const char *buf, size_t count)
/* Forcibly offline a page, including killing processes. */
static ssize_t
-store_hard_offline_page(struct class *class, const char *buf, size_t count)
+store_hard_offline_page(struct sysdev_class *class,
+ struct sysdev_class_attribute *class_attr,
+ const char *buf, size_t count)
{
int ret;
u64 pfn;
@@ -397,18 +405,18 @@ store_hard_offline_page(struct class *class, const char *buf, size_t count)
return ret ? ret : count;
}
-static CLASS_ATTR(soft_offline_page, 0644, NULL, store_soft_offline_page);
-static CLASS_ATTR(hard_offline_page, 0644, NULL, store_hard_offline_page);
+static SYSDEV_CLASS_ATTR(soft_offline_page, 0644, NULL, store_soft_offline_page);
+static SYSDEV_CLASS_ATTR(hard_offline_page, 0644, NULL, store_hard_offline_page);
static __init int memory_fail_init(void)
{
int err;
err = sysfs_create_file(&memory_sysdev_class.kset.kobj,
- &class_attr_soft_offline_page.attr);
+ &attr_soft_offline_page.attr);
if (!err)
err = sysfs_create_file(&memory_sysdev_class.kset.kobj,
- &class_attr_hard_offline_page.attr);
+ &attr_hard_offline_page.attr);
return err;
}
#else
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 31be3ac2e21..e023682be2c 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -669,7 +669,7 @@ config VIRTIO_CONSOLE
config HVCS
tristate "IBM Hypervisor Virtual Console Server support"
- depends on PPC_PSERIES
+ depends on PPC_PSERIES && HVC_CONSOLE
help
Partitionable IBM Power5 ppc64 machines allow hosting of
firmware virtual consoles from one Linux partition by
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 5aa7a586a7f..1afb8968a34 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -725,12 +725,11 @@ static struct pci_driver agp_amd64_pci_driver = {
int __init agp_amd64_init(void)
{
int err = 0;
- static int done = 0;
if (agp_off)
return -EINVAL;
- if (done++)
+ if (gart_iommu_aperture)
return agp_bridges_found ? 0 : -ENODEV;
err = pci_register_driver(&agp_amd64_pci_driver);
@@ -771,6 +770,8 @@ int __init agp_amd64_init(void)
static void __exit agp_amd64_cleanup(void)
{
+ if (gart_iommu_aperture)
+ return;
if (aperture_resource)
release_resource(aperture_resource);
pci_unregister_driver(&agp_amd64_pci_driver);
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 30c36ac2cd0..3999a5f25f3 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -2460,10 +2460,14 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
&bridge->mode);
}
- if (bridge->driver->mask_memory == intel_i965_mask_memory)
+ if (bridge->driver->mask_memory == intel_i965_mask_memory) {
if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(36)))
dev_err(&intel_private.pcidev->dev,
"set gfx device dma mask 36bit failed!\n");
+ else
+ pci_set_consistent_dma_mask(intel_private.pcidev,
+ DMA_BIT_MASK(36));
+ }
pci_set_drvdata(pdev, bridge);
return agp_add_bridge(bridge);
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
index bdaef8e9402..64fe0a793ef 100644
--- a/drivers/char/hw_random/virtio-rng.c
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -114,7 +114,7 @@ static struct virtio_device_id id_table[] = {
{ 0 },
};
-static struct virtio_driver virtio_rng = {
+static struct virtio_driver virtio_rng_driver = {
.driver.name = KBUILD_MODNAME,
.driver.owner = THIS_MODULE,
.id_table = id_table,
@@ -124,12 +124,12 @@ static struct virtio_driver virtio_rng = {
static int __init init(void)
{
- return register_virtio_driver(&virtio_rng);
+ return register_virtio_driver(&virtio_rng_driver);
}
static void __exit fini(void)
{
- unregister_virtio_driver(&virtio_rng);
+ unregister_virtio_driver(&virtio_rng_driver);
}
module_init(init);
module_exit(fini);
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index c5facd951dd..000dc67b85b 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -197,7 +197,7 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
edac_printk(KERN_DEBUG, EDAC_MC,
"pci-read, sdram scrub control value: %d \n", scrubval);
- for (i = 0; ARRAY_SIZE(scrubrates); i++) {
+ for (i = 0; i < ARRAY_SIZE(scrubrates); i++) {
if (scrubrates[i].scrubval == scrubval) {
*bw = scrubrates[i].bandwidth;
status = 0;
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
index 77a9579d716..adc10a2ac5f 100644
--- a/drivers/edac/i5000_edac.c
+++ b/drivers/edac/i5000_edac.c
@@ -577,7 +577,13 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
debugf0("\tUncorrected bits= 0x%x\n", ue_errors);
branch = EXTRACT_FBDCHAN_INDX(info->ferr_nf_fbd);
- channel = branch;
+
+ /*
+ * According with i5000 datasheet, bit 28 has no significance
+ * for errors M4Err-M12Err and M17Err-M21Err, on FERR_NF_FBD
+ */
+ channel = branch & 2;
+
bank = NREC_BANK(info->nrecmema);
rank = NREC_RANK(info->nrecmema);
rdwr = NREC_RDWR(info->nrecmema);
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index bbe47812e4b..e660ac07f3b 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -134,6 +134,10 @@ static int i915_init_phys_hws(struct drm_device *dev)
memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
+ if (IS_I965G(dev))
+ dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) &
+ 0xf0;
+
I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
DRM_DEBUG_DRIVER("Enabled hardware status page\n");
return 0;
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index be631cc3e4d..46d88965852 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -45,6 +45,9 @@ module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
unsigned int i915_powersave = 1;
module_param_named(powersave, i915_powersave, int, 0400);
+unsigned int i915_lvds_downclock = 0;
+module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
+
static struct drm_driver driver;
#define INTEL_VGA_DEVICE(id, info) { \
@@ -464,8 +467,11 @@ static struct drm_driver driver = {
.lastclose = i915_driver_lastclose,
.preclose = i915_driver_preclose,
.postclose = i915_driver_postclose,
+
+ /* Used in place of i915_pm_ops for non-DRIVER_MODESET */
.suspend = i915_suspend,
.resume = i915_resume,
+
.device_is_agp = i915_driver_device_is_agp,
.enable_vblank = i915_enable_vblank,
.disable_vblank = i915_disable_vblank,
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 29dd6762696..2c1669488b5 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -283,6 +283,7 @@ typedef struct drm_i915_private {
unsigned int lvds_use_ssc:1;
unsigned int edp_support:1;
int lvds_ssc_freq;
+ int edp_bpp;
struct notifier_block lid_notifier;
@@ -722,6 +723,7 @@ extern struct drm_ioctl_desc i915_ioctls[];
extern int i915_max_ioctl;
extern unsigned int i915_fbpercrtc;
extern unsigned int i915_powersave;
+extern unsigned int i915_lvds_downclock;
extern void i915_save_display(struct drm_device *dev);
extern void i915_restore_display(struct drm_device *dev);
@@ -864,6 +866,7 @@ int i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptib
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj,
int write);
+int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj);
int i915_gem_attach_phys_object(struct drm_device *dev,
struct drm_gem_object *obj, int id);
void i915_gem_detach_phys_object(struct drm_device *dev,
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 2748609f05b..0c67924ca80 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2837,6 +2837,57 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write)
return 0;
}
+/*
+ * Prepare buffer for display plane. Use uninterruptible for possible flush
+ * wait, as in modesetting process we're not supposed to be interrupted.
+ */
+int
+i915_gem_object_set_to_display_plane(struct drm_gem_object *obj)
+{
+ struct drm_device *dev = obj->dev;
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ uint32_t old_write_domain, old_read_domains;
+ int ret;
+
+ /* Not valid to be called on unbound objects. */
+ if (obj_priv->gtt_space == NULL)
+ return -EINVAL;
+
+ i915_gem_object_flush_gpu_write_domain(obj);
+
+ /* Wait on any GPU rendering and flushing to occur. */
+ if (obj_priv->active) {
+#if WATCH_BUF
+ DRM_INFO("%s: object %p wait for seqno %08x\n",
+ __func__, obj, obj_priv->last_rendering_seqno);
+#endif
+ ret = i915_do_wait_request(dev, obj_priv->last_rendering_seqno, 0);
+ if (ret != 0)
+ return ret;
+ }
+
+ old_write_domain = obj->write_domain;
+ old_read_domains = obj->read_domains;
+
+ obj->read_domains &= I915_GEM_DOMAIN_GTT;
+
+ i915_gem_object_flush_cpu_write_domain(obj);
+
+ /* It should now be out of any other write domains, and we can update
+ * the domain values for our changes.
+ */
+ BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
+ obj->read_domains |= I915_GEM_DOMAIN_GTT;
+ obj->write_domain = I915_GEM_DOMAIN_GTT;
+ obj_priv->dirty = 1;
+
+ trace_i915_gem_object_change_domain(obj,
+ old_read_domains,
+ old_write_domain);
+
+ return 0;
+}
+
/**
* Moves a single object to the CPU read, and possibly write domain.
*
@@ -4000,8 +4051,6 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
"back to user (%d)\n",
args->buffer_count, ret);
}
- } else {
- DRM_ERROR("i915_gem_do_execbuffer returns %d\n", ret);
}
drm_free_large(exec_list);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 7cd8110051b..89a071a3e6f 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -274,7 +274,6 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int ret = IRQ_NONE;
u32 de_iir, gt_iir, de_ier, pch_iir;
- u32 new_de_iir, new_gt_iir, new_pch_iir;
struct drm_i915_master_private *master_priv;
/* disable master interrupt before clearing iir */
@@ -286,51 +285,42 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
gt_iir = I915_READ(GTIIR);
pch_iir = I915_READ(SDEIIR);
- for (;;) {
- if (de_iir == 0 && gt_iir == 0 && pch_iir == 0)
- break;
-
- ret = IRQ_HANDLED;
+ if (de_iir == 0 && gt_iir == 0 && pch_iir == 0)
+ goto done;
- /* should clear PCH hotplug event before clear CPU irq */
- I915_WRITE(SDEIIR, pch_iir);
- new_pch_iir = I915_READ(SDEIIR);
+ ret = IRQ_HANDLED;
- I915_WRITE(DEIIR, de_iir);
- new_de_iir = I915_READ(DEIIR);
- I915_WRITE(GTIIR, gt_iir);
- new_gt_iir = I915_READ(GTIIR);
-
- if (dev->primary->master) {
- master_priv = dev->primary->master->driver_priv;
- if (master_priv->sarea_priv)
- master_priv->sarea_priv->last_dispatch =
- READ_BREADCRUMB(dev_priv);
- }
-
- if (gt_iir & GT_USER_INTERRUPT) {
- u32 seqno = i915_get_gem_seqno(dev);
- dev_priv->mm.irq_gem_seqno = seqno;
- trace_i915_gem_request_complete(dev, seqno);
- DRM_WAKEUP(&dev_priv->irq_queue);
- dev_priv->hangcheck_count = 0;
- mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
- }
+ if (dev->primary->master) {
+ master_priv = dev->primary->master->driver_priv;
+ if (master_priv->sarea_priv)
+ master_priv->sarea_priv->last_dispatch =
+ READ_BREADCRUMB(dev_priv);
+ }
- if (de_iir & DE_GSE)
- ironlake_opregion_gse_intr(dev);
+ if (gt_iir & GT_USER_INTERRUPT) {
+ u32 seqno = i915_get_gem_seqno(dev);
+ dev_priv->mm.irq_gem_seqno = seqno;
+ trace_i915_gem_request_complete(dev, seqno);
+ DRM_WAKEUP(&dev_priv->irq_queue);
+ dev_priv->hangcheck_count = 0;
+ mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
+ }
- /* check event from PCH */
- if ((de_iir & DE_PCH_EVENT) &&
- (pch_iir & SDE_HOTPLUG_MASK)) {
- queue_work(dev_priv->wq, &dev_priv->hotplug_work);
- }
+ if (de_iir & DE_GSE)
+ ironlake_opregion_gse_intr(dev);
- de_iir = new_de_iir;
- gt_iir = new_gt_iir;
- pch_iir = new_pch_iir;
+ /* check event from PCH */
+ if ((de_iir & DE_PCH_EVENT) &&
+ (pch_iir & SDE_HOTPLUG_MASK)) {
+ queue_work(dev_priv->wq, &dev_priv->hotplug_work);
}
+ /* should clear PCH hotplug event before clear CPU irq */
+ I915_WRITE(SDEIIR, pch_iir);
+ I915_WRITE(GTIIR, gt_iir);
+ I915_WRITE(DEIIR, de_iir);
+
+done:
I915_WRITE(DEIER, de_ier);
(void)I915_READ(DEIER);
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 149d360d64a..847006c5218 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1815,7 +1815,7 @@
#define DSPFW_PLANEB_SHIFT 8
#define DSPFW2 0x70038
#define DSPFW_CURSORA_MASK 0x00003f00
-#define DSPFW_CURSORA_SHIFT 16
+#define DSPFW_CURSORA_SHIFT 8
#define DSPFW3 0x7003c
#define DSPFW_HPLL_SR_EN (1<<31)
#define DSPFW_CURSOR_SR_SHIFT 24
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index f2756774758..15fbc1b5a83 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -33,6 +33,8 @@
#define SLAVE_ADDR1 0x70
#define SLAVE_ADDR2 0x72
+static int panel_type;
+
static void *
find_section(struct bdb_header *bdb, int section_id)
{
@@ -128,6 +130,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
dev_priv->lvds_dither = lvds_options->pixel_dither;
if (lvds_options->panel_type == 0xff)
return;
+ panel_type = lvds_options->panel_type;
lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA);
if (!lvds_lfp_data)
@@ -197,7 +200,8 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
memset(temp_mode, 0, sizeof(*temp_mode));
}
kfree(temp_mode);
- if (temp_downclock < panel_fixed_mode->clock) {
+ if (temp_downclock < panel_fixed_mode->clock &&
+ i915_lvds_downclock) {
dev_priv->lvds_downclock_avail = 1;
dev_priv->lvds_downclock = temp_downclock;
DRM_DEBUG_KMS("LVDS downclock is found in VBT. ",
@@ -405,6 +409,34 @@ parse_driver_features(struct drm_i915_private *dev_priv,
}
static void
+parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
+{
+ struct bdb_edp *edp;
+
+ edp = find_section(bdb, BDB_EDP);
+ if (!edp) {
+ if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp_support) {
+ DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported,\
+ assume 18bpp panel color depth.\n");
+ dev_priv->edp_bpp = 18;
+ }
+ return;
+ }
+
+ switch ((edp->color_depth >> (panel_type * 2)) & 3) {
+ case EDP_18BPP:
+ dev_priv->edp_bpp = 18;
+ break;
+ case EDP_24BPP:
+ dev_priv->edp_bpp = 24;
+ break;
+ case EDP_30BPP:
+ dev_priv->edp_bpp = 30;
+ break;
+ }
+}
+
+static void
parse_device_mapping(struct drm_i915_private *dev_priv,
struct bdb_header *bdb)
{
@@ -521,6 +553,7 @@ intel_init_bios(struct drm_device *dev)
parse_sdvo_device_mapping(dev_priv, bdb);
parse_device_mapping(dev_priv, bdb);
parse_driver_features(dev_priv, bdb);
+ parse_edp(dev_priv, bdb);
pci_unmap_rom(pdev, bios);
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h
index 425ac9d7f72..4c18514f6f8 100644
--- a/drivers/gpu/drm/i915/intel_bios.h
+++ b/drivers/gpu/drm/i915/intel_bios.h
@@ -98,6 +98,7 @@ struct vbios_data {
#define BDB_SDVO_LVDS_PNP_IDS 24
#define BDB_SDVO_LVDS_POWER_SEQ 25
#define BDB_TV_OPTIONS 26
+#define BDB_EDP 27
#define BDB_LVDS_OPTIONS 40
#define BDB_LVDS_LFP_DATA_PTRS 41
#define BDB_LVDS_LFP_DATA 42
@@ -426,6 +427,45 @@ struct bdb_driver_features {
u8 custom_vbt_version;
} __attribute__((packed));
+#define EDP_18BPP 0
+#define EDP_24BPP 1
+#define EDP_30BPP 2
+#define EDP_RATE_1_62 0
+#define EDP_RATE_2_7 1
+#define EDP_LANE_1 0
+#define EDP_LANE_2 1
+#define EDP_LANE_4 3
+#define EDP_PREEMPHASIS_NONE 0
+#define EDP_PREEMPHASIS_3_5dB 1
+#define EDP_PREEMPHASIS_6dB 2
+#define EDP_PREEMPHASIS_9_5dB 3
+#define EDP_VSWING_0_4V 0
+#define EDP_VSWING_0_6V 1
+#define EDP_VSWING_0_8V 2
+#define EDP_VSWING_1_2V 3
+
+struct edp_power_seq {
+ u16 t3;
+ u16 t7;
+ u16 t9;
+ u16 t10;
+ u16 t12;
+} __attribute__ ((packed));
+
+struct edp_link_params {
+ u8 rate:4;
+ u8 lanes:4;
+ u8 preemphasis:4;
+ u8 vswing:4;
+} __attribute__ ((packed));
+
+struct bdb_edp {
+ struct edp_power_seq power_seqs[16];
+ u32 color_depth;
+ u32 sdrrs_msa_timing_delay;
+ struct edp_link_params link_params[16];
+} __attribute__ ((packed));
+
bool intel_init_bios(struct drm_device *dev);
/*
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 002612fae71..45da78ef4a9 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -70,8 +70,6 @@ struct intel_limit {
intel_p2_t p2;
bool (* find_pll)(const intel_limit_t *, struct drm_crtc *,
int, int, intel_clock_t *);
- bool (* find_reduced_pll)(const intel_limit_t *, struct drm_crtc *,
- int, int, intel_clock_t *);
};
#define I8XX_DOT_MIN 25000
@@ -243,11 +241,11 @@ struct intel_limit {
#define IRONLAKE_VCO_MIN 1760000
#define IRONLAKE_VCO_MAX 3510000
#define IRONLAKE_N_MIN 1
-#define IRONLAKE_N_MAX 5
+#define IRONLAKE_N_MAX 6
#define IRONLAKE_M_MIN 79
-#define IRONLAKE_M_MAX 118
+#define IRONLAKE_M_MAX 127
#define IRONLAKE_M1_MIN 12
-#define IRONLAKE_M1_MAX 23
+#define IRONLAKE_M1_MAX 22
#define IRONLAKE_M2_MIN 5
#define IRONLAKE_M2_MAX 9
#define IRONLAKE_P_SDVO_DAC_MIN 5
@@ -274,9 +272,6 @@ static bool
intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock);
static bool
-intel_find_best_reduced_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *best_clock);
-static bool
intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock);
@@ -299,7 +294,6 @@ static const intel_limit_t intel_limits_i8xx_dvo = {
.p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT,
.p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST },
.find_pll = intel_find_best_PLL,
- .find_reduced_pll = intel_find_best_reduced_PLL,
};
static const intel_limit_t intel_limits_i8xx_lvds = {
@@ -314,7 +308,6 @@ static const intel_limit_t intel_limits_i8xx_lvds = {
.p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT,
.p2_slow = I8XX_P2_LVDS_SLOW, .p2_fast = I8XX_P2_LVDS_FAST },
.find_pll = intel_find_best_PLL,
- .find_reduced_pll = intel_find_best_reduced_PLL,
};
static const intel_limit_t intel_limits_i9xx_sdvo = {
@@ -329,7 +322,6 @@ static const intel_limit_t intel_limits_i9xx_sdvo = {
.p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
.p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST },
.find_pll = intel_find_best_PLL,
- .find_reduced_pll = intel_find_best_reduced_PLL,
};
static const intel_limit_t intel_limits_i9xx_lvds = {
@@ -347,7 +339,6 @@ static const intel_limit_t intel_limits_i9xx_lvds = {
.p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
.p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST },
.find_pll = intel_find_best_PLL,
- .find_reduced_pll = intel_find_best_reduced_PLL,
};
/* below parameter and function is for G4X Chipset Family*/
@@ -365,7 +356,6 @@ static const intel_limit_t intel_limits_g4x_sdvo = {
.p2_fast = G4X_P2_SDVO_FAST
},
.find_pll = intel_g4x_find_best_PLL,
- .find_reduced_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_g4x_hdmi = {
@@ -382,7 +372,6 @@ static const intel_limit_t intel_limits_g4x_hdmi = {
.p2_fast = G4X_P2_HDMI_DAC_FAST
},
.find_pll = intel_g4x_find_best_PLL,
- .find_reduced_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
@@ -407,7 +396,6 @@ static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
.p2_fast = G4X_P2_SINGLE_CHANNEL_LVDS_FAST
},
.find_pll = intel_g4x_find_best_PLL,
- .find_reduced_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
@@ -432,7 +420,6 @@ static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
.p2_fast = G4X_P2_DUAL_CHANNEL_LVDS_FAST
},
.find_pll = intel_g4x_find_best_PLL,
- .find_reduced_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_g4x_display_port = {
@@ -470,7 +457,6 @@ static const intel_limit_t intel_limits_pineview_sdvo = {
.p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
.p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST },
.find_pll = intel_find_best_PLL,
- .find_reduced_pll = intel_find_best_reduced_PLL,
};
static const intel_limit_t intel_limits_pineview_lvds = {
@@ -486,7 +472,6 @@ static const intel_limit_t intel_limits_pineview_lvds = {
.p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
.p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_SLOW },
.find_pll = intel_find_best_PLL,
- .find_reduced_pll = intel_find_best_reduced_PLL,
};
static const intel_limit_t intel_limits_ironlake_sdvo = {
@@ -768,46 +753,6 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
return (err != target);
}
-
-static bool
-intel_find_best_reduced_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *best_clock)
-
-{
- struct drm_device *dev = crtc->dev;
- intel_clock_t clock;
- int err = target;
- bool found = false;
-
- memcpy(&clock, best_clock, sizeof(intel_clock_t));
-
- for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
- for (clock.m2 = limit->m2.min; clock.m2 <= limit->m2.max; clock.m2++) {
- /* m1 is always 0 in Pineview */
- if (clock.m2 >= clock.m1 && !IS_PINEVIEW(dev))
- break;
- for (clock.n = limit->n.min; clock.n <= limit->n.max;
- clock.n++) {
- int this_err;
-
- intel_clock(dev, refclk, &clock);
-
- if (!intel_PLL_is_valid(crtc, &clock))
- continue;
-
- this_err = abs(clock.dot - target);
- if (this_err < err) {
- *best_clock = clock;
- err = this_err;
- found = true;
- }
- }
- }
- }
-
- return found;
-}
-
static bool
intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock)
@@ -1262,7 +1207,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
return ret;
}
- ret = i915_gem_object_set_to_gtt_domain(obj, 1);
+ ret = i915_gem_object_set_to_display_plane(obj);
if (ret != 0) {
i915_gem_object_unpin(obj);
mutex_unlock(&dev->struct_mutex);
@@ -2910,10 +2855,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
return -EINVAL;
}
- if (is_lvds && limit->find_reduced_pll &&
- dev_priv->lvds_downclock_avail) {
- memcpy(&reduced_clock, &clock, sizeof(intel_clock_t));
- has_reduced_clock = limit->find_reduced_pll(limit, crtc,
+ if (is_lvds && dev_priv->lvds_downclock_avail) {
+ has_reduced_clock = limit->find_pll(limit, crtc,
dev_priv->lvds_downclock,
refclk,
&reduced_clock);
@@ -2981,6 +2924,21 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
temp |= PIPE_8BPC;
else
temp |= PIPE_6BPC;
+ } else if (is_edp) {
+ switch (dev_priv->edp_bpp/3) {
+ case 8:
+ temp |= PIPE_8BPC;
+ break;
+ case 10:
+ temp |= PIPE_10BPC;
+ break;
+ case 6:
+ temp |= PIPE_6BPC;
+ break;
+ case 12:
+ temp |= PIPE_12BPC;
+ break;
+ }
} else
temp |= PIPE_8BPC;
I915_WRITE(pipeconf_reg, temp);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 1349d9fd01c..439506cefc1 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -125,9 +125,15 @@ intel_dp_link_clock(uint8_t link_bw)
/* I think this is a fiction */
static int
-intel_dp_link_required(int pixel_clock)
+intel_dp_link_required(struct drm_device *dev,
+ struct intel_output *intel_output, int pixel_clock)
{
- return pixel_clock * 3;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (IS_eDP(intel_output))
+ return (pixel_clock * dev_priv->edp_bpp) / 8;
+ else
+ return pixel_clock * 3;
}
static int
@@ -138,7 +144,8 @@ intel_dp_mode_valid(struct drm_connector *connector,
int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_output));
int max_lanes = intel_dp_max_lane_count(intel_output);
- if (intel_dp_link_required(mode->clock) > max_link_clock * max_lanes)
+ if (intel_dp_link_required(connector->dev, intel_output, mode->clock)
+ > max_link_clock * max_lanes)
return MODE_CLOCK_HIGH;
if (mode->clock < 10000)
@@ -492,7 +499,8 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
for (clock = 0; clock <= max_clock; clock++) {
int link_avail = intel_dp_link_clock(bws[clock]) * lane_count;
- if (intel_dp_link_required(mode->clock) <= link_avail) {
+ if (intel_dp_link_required(encoder->dev, intel_output, mode->clock)
+ <= link_avail) {
dp_priv->link_bw = bws[clock];
dp_priv->lane_count = lane_count;
adjusted_mode->clock = intel_dp_link_clock(dp_priv->link_bw);
@@ -1289,53 +1297,7 @@ intel_dp_hot_plug(struct intel_output *intel_output)
if (dp_priv->dpms_mode == DRM_MODE_DPMS_ON)
intel_dp_check_link_status(intel_output);
}
-/*
- * Enumerate the child dev array parsed from VBT to check whether
- * the given DP is present.
- * If it is present, return 1.
- * If it is not present, return false.
- * If no child dev is parsed from VBT, it is assumed that the given
- * DP is present.
- */
-static int dp_is_present_in_vbt(struct drm_device *dev, int dp_reg)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct child_device_config *p_child;
- int i, dp_port, ret;
-
- if (!dev_priv->child_dev_num)
- return 1;
-
- dp_port = 0;
- if (dp_reg == DP_B || dp_reg == PCH_DP_B)
- dp_port = PORT_IDPB;
- else if (dp_reg == DP_C || dp_reg == PCH_DP_C)
- dp_port = PORT_IDPC;
- else if (dp_reg == DP_D || dp_reg == PCH_DP_D)
- dp_port = PORT_IDPD;
-
- ret = 0;
- for (i = 0; i < dev_priv->child_dev_num; i++) {
- p_child = dev_priv->child_dev + i;
- /*
- * If the device type is not DP, continue.
- */
- if (p_child->device_type != DEVICE_TYPE_DP &&
- p_child->device_type != DEVICE_TYPE_eDP)
- continue;
- /* Find the eDP port */
- if (dp_reg == DP_A && p_child->device_type == DEVICE_TYPE_eDP) {
- ret = 1;
- break;
- }
- /* Find the DP port */
- if (p_child->dvo_port == dp_port) {
- ret = 1;
- break;
- }
- }
- return ret;
-}
+
void
intel_dp_init(struct drm_device *dev, int output_reg)
{
@@ -1345,10 +1307,6 @@ intel_dp_init(struct drm_device *dev, int output_reg)
struct intel_dp_priv *dp_priv;
const char *name = NULL;
- if (!dp_is_present_in_vbt(dev, output_reg)) {
- DRM_DEBUG_KMS("DP is not present. Ignore it\n");
- return;
- }
intel_output = kcalloc(sizeof(struct intel_output) +
sizeof(struct intel_dp_priv), 1, GFP_KERNEL);
if (!intel_output)
@@ -1373,11 +1331,10 @@ intel_dp_init(struct drm_device *dev, int output_reg)
else if (output_reg == DP_D || output_reg == PCH_DP_D)
intel_output->clone_mask = (1 << INTEL_DP_D_CLONE_BIT);
- if (IS_eDP(intel_output)) {
- intel_output->crtc_mask = (1 << 1);
+ if (IS_eDP(intel_output))
intel_output->clone_mask = (1 << INTEL_EDP_CLONE_BIT);
- } else
- intel_output->crtc_mask = (1 << 0) | (1 << 1);
+
+ intel_output->crtc_mask = (1 << 0) | (1 << 1);
connector->interlace_allowed = true;
connector->doublescan_allowed = 0;
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 06431941b23..0e268deed76 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -225,52 +225,6 @@ static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
.destroy = intel_hdmi_enc_destroy,
};
-/*
- * Enumerate the child dev array parsed from VBT to check whether
- * the given HDMI is present.
- * If it is present, return 1.
- * If it is not present, return false.
- * If no child dev is parsed from VBT, it assumes that the given
- * HDMI is present.
- */
-static int hdmi_is_present_in_vbt(struct drm_device *dev, int hdmi_reg)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct child_device_config *p_child;
- int i, hdmi_port, ret;
-
- if (!dev_priv->child_dev_num)
- return 1;
-
- if (hdmi_reg == SDVOB)
- hdmi_port = DVO_B;
- else if (hdmi_reg == SDVOC)
- hdmi_port = DVO_C;
- else if (hdmi_reg == HDMIB)
- hdmi_port = DVO_B;
- else if (hdmi_reg == HDMIC)
- hdmi_port = DVO_C;
- else if (hdmi_reg == HDMID)
- hdmi_port = DVO_D;
- else
- return 0;
-
- ret = 0;
- for (i = 0; i < dev_priv->child_dev_num; i++) {
- p_child = dev_priv->child_dev + i;
- /*
- * If the device type is not HDMI, continue.
- */
- if (p_child->device_type != DEVICE_TYPE_HDMI)
- continue;
- /* Find the HDMI port */
- if (p_child->dvo_port == hdmi_port) {
- ret = 1;
- break;
- }
- }
- return ret;
-}
void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -278,10 +232,6 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
struct intel_output *intel_output;
struct intel_hdmi_priv *hdmi_priv;
- if (!hdmi_is_present_in_vbt(dev, sdvox_reg)) {
- DRM_DEBUG_KMS("HDMI is not present. Ignored it \n");
- return;
- }
intel_output = kcalloc(sizeof(struct intel_output) +
sizeof(struct intel_hdmi_priv), 1, GFP_KERNEL);
if (!intel_output)
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index f4b4aa242df..aa74e59bec6 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -602,6 +602,20 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
/* Some lid devices report incorrect lid status, assume they're connected */
static const struct dmi_system_id bad_lid_status[] = {
{
+ .ident = "Compaq nx9020",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_BOARD_NAME, "3084"),
+ },
+ },
+ {
+ .ident = "Samsung SX20S",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Phoenix Technologies LTD"),
+ DMI_MATCH(DMI_BOARD_NAME, "SX20S"),
+ },
+ },
+ {
.ident = "Aspire One",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -912,7 +926,8 @@ static void intel_find_lvds_downclock(struct drm_device *dev,
}
}
mutex_unlock(&dev->mode_config.mutex);
- if (temp_downclock < panel_fixed_mode->clock) {
+ if (temp_downclock < panel_fixed_mode->clock &&
+ i915_lvds_downclock) {
/* We found the downclock for LVDS. */
dev_priv->lvds_downclock_avail = 1;
dev_priv->lvds_downclock = temp_downclock;
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index de5144c8c15..eaacfd0920d 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -462,14 +462,63 @@ static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
}
/**
- * Don't check status code from this as it switches the bus back to the
- * SDVO chips which defeats the purpose of doing a bus switch in the first
- * place.
+ * Try to read the response after issuie the DDC switch command. But it
+ * is noted that we must do the action of reading response and issuing DDC
+ * switch command in one I2C transaction. Otherwise when we try to start
+ * another I2C transaction after issuing the DDC bus switch, it will be
+ * switched to the internal SDVO register.
*/
static void intel_sdvo_set_control_bus_switch(struct intel_output *intel_output,
u8 target)
{
- intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1);
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ u8 out_buf[2], cmd_buf[2], ret_value[2], ret;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = sdvo_priv->slave_addr >> 1,
+ .flags = 0,
+ .len = 2,
+ .buf = out_buf,
+ },
+ /* the following two are to read the response */
+ {
+ .addr = sdvo_priv->slave_addr >> 1,
+ .flags = 0,
+ .len = 1,
+ .buf = cmd_buf,
+ },
+ {
+ .addr = sdvo_priv->slave_addr >> 1,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = ret_value,
+ },
+ };
+
+ intel_sdvo_debug_write(intel_output, SDVO_CMD_SET_CONTROL_BUS_SWITCH,
+ &target, 1);
+ /* write the DDC switch command argument */
+ intel_sdvo_write_byte(intel_output, SDVO_I2C_ARG_0, target);
+
+ out_buf[0] = SDVO_I2C_OPCODE;
+ out_buf[1] = SDVO_CMD_SET_CONTROL_BUS_SWITCH;
+ cmd_buf[0] = SDVO_I2C_CMD_STATUS;
+ cmd_buf[1] = 0;
+ ret_value[0] = 0;
+ ret_value[1] = 0;
+
+ ret = i2c_transfer(intel_output->i2c_bus, msgs, 3);
+ if (ret != 3) {
+ /* failure in I2C transfer */
+ DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
+ return;
+ }
+ if (ret_value[0] != SDVO_CMD_STATUS_SUCCESS) {
+ DRM_DEBUG_KMS("DDC switch command returns response %d\n",
+ ret_value[0]);
+ return;
+ }
+ return;
}
static bool intel_sdvo_set_target_input(struct intel_output *intel_output, bool target_0, bool target_1)
@@ -1579,6 +1628,32 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)
edid = drm_get_edid(&intel_output->base,
intel_output->ddc_bus);
+ /* This is only applied to SDVO cards with multiple outputs */
+ if (edid == NULL && intel_sdvo_multifunc_encoder(intel_output)) {
+ uint8_t saved_ddc, temp_ddc;
+ saved_ddc = sdvo_priv->ddc_bus;
+ temp_ddc = sdvo_priv->ddc_bus >> 1;
+ /*
+ * Don't use the 1 as the argument of DDC bus switch to get
+ * the EDID. It is used for SDVO SPD ROM.
+ */
+ while(temp_ddc > 1) {
+ sdvo_priv->ddc_bus = temp_ddc;
+ edid = drm_get_edid(&intel_output->base,
+ intel_output->ddc_bus);
+ if (edid) {
+ /*
+ * When we can get the EDID, maybe it is the
+ * correct DDC bus. Update it.
+ */
+ sdvo_priv->ddc_bus = temp_ddc;
+ break;
+ }
+ temp_ddc >>= 1;
+ }
+ if (edid == NULL)
+ sdvo_priv->ddc_bus = saved_ddc;
+ }
/* when there is no edid and no monitor is connected with VGA
* port, try to use the CRT ddc to read the EDID for DVI-connector
*/
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 1d5b9b7b033..552ec110b74 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1840,8 +1840,6 @@ intel_tv_init(struct drm_device *dev)
drm_connector_attach_property(connector,
dev->mode_config.tv_bottom_margin_property,
tv_priv->margin[TV_MARGIN_BOTTOM]);
-
- dev_priv->hotplug_supported_mask |= TV_HOTPLUG_INT_STATUS;
out:
drm_sysfs_connector_add(connector);
}
diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c
index f70f46582c6..4687af40dd5 100644
--- a/drivers/i2c/busses/i2c-ali1563.c
+++ b/drivers/i2c/busses/i2c-ali1563.c
@@ -87,9 +87,9 @@ static int ali1563_transaction(struct i2c_adapter * a, int size)
outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_START, SMB_HST_CNTL2);
timeout = ALI1563_MAX_TIMEOUT;
- do
+ do {
msleep(1);
- while (((data = inb_p(SMB_HST_STS)) & HST_STS_BUSY) && --timeout);
+ } while (((data = inb_p(SMB_HST_STS)) & HST_STS_BUSY) && --timeout);
dev_dbg(&a->dev, "Transaction (post): STS=%02x, CNTL1=%02x, "
"CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
@@ -157,9 +157,9 @@ static int ali1563_block_start(struct i2c_adapter * a)
outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_START, SMB_HST_CNTL2);
timeout = ALI1563_MAX_TIMEOUT;
- do
+ do {
msleep(1);
- while (!((data = inb_p(SMB_HST_STS)) & HST_STS_DONE) && --timeout);
+ } while (!((data = inb_p(SMB_HST_STS)) & HST_STS_DONE) && --timeout);
dev_dbg(&a->dev, "Block (post): STS=%02x, CNTL1=%02x, "
"CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
index 0ed68e2ccd2..f7346a9bd95 100644
--- a/drivers/i2c/busses/i2c-pca-isa.c
+++ b/drivers/i2c/busses/i2c-pca-isa.c
@@ -75,7 +75,7 @@ static int pca_isa_waitforcompletion(void *pd)
unsigned long timeout;
if (irq > -1) {
- ret = wait_event_interruptible_timeout(pca_wait,
+ ret = wait_event_timeout(pca_wait,
pca_isa_readbyte(pd, I2C_PCA_CON)
& I2C_PCA_CON_SI, pca_isa_ops.timeout);
} else {
@@ -96,7 +96,7 @@ static void pca_isa_resetchip(void *pd)
}
static irqreturn_t pca_handler(int this_irq, void *dev_id) {
- wake_up_interruptible(&pca_wait);
+ wake_up(&pca_wait);
return IRQ_HANDLED;
}
diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c
index c4df9d411cd..5b2213df5ed 100644
--- a/drivers/i2c/busses/i2c-pca-platform.c
+++ b/drivers/i2c/busses/i2c-pca-platform.c
@@ -84,7 +84,7 @@ static int i2c_pca_pf_waitforcompletion(void *pd)
unsigned long timeout;
if (i2c->irq) {
- ret = wait_event_interruptible_timeout(i2c->wait,
+ ret = wait_event_timeout(i2c->wait,
i2c->algo_data.read_byte(i2c, I2C_PCA_CON)
& I2C_PCA_CON_SI, i2c->adap.timeout);
} else {
@@ -122,7 +122,7 @@ static irqreturn_t i2c_pca_pf_handler(int this_irq, void *dev_id)
if ((i2c->algo_data.read_byte(i2c, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0)
return IRQ_NONE;
- wake_up_interruptible(&i2c->wait);
+ wake_up(&i2c->wait);
return IRQ_HANDLED;
}
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 1e245e9cad3..e56e4b6823c 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -324,12 +324,12 @@ static int piix4_transaction(void)
else
msleep(1);
- while ((timeout++ < MAX_TIMEOUT) &&
+ while ((++timeout < MAX_TIMEOUT) &&
((temp = inb_p(SMBHSTSTS)) & 0x01))
msleep(1);
/* If the SMBus is still busy, we give up */
- if (timeout >= MAX_TIMEOUT) {
+ if (timeout == MAX_TIMEOUT) {
dev_err(&piix4_adapter.dev, "SMBus Timeout!\n");
result = -ETIMEDOUT;
}
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index e4b1543015a..a84a909e123 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -165,10 +165,10 @@ static int vt596_transaction(u8 size)
do {
msleep(1);
temp = inb_p(SMBHSTSTS);
- } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
+ } while ((temp & 0x01) && (++timeout < MAX_TIMEOUT));
/* If the SMBus is still busy, we give up */
- if (timeout >= MAX_TIMEOUT) {
+ if (timeout == MAX_TIMEOUT) {
result = -ETIMEDOUT;
dev_err(&vt596_adapter.dev, "SMBus timeout!\n");
}
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 0ac2f90ab84..10be7b5fbe9 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -248,7 +248,7 @@ static const struct attribute_group *i2c_dev_attr_groups[] = {
NULL
};
-const static struct dev_pm_ops i2c_device_pm_ops = {
+static const struct dev_pm_ops i2c_device_pm_ops = {
.suspend = i2c_device_pm_suspend,
.resume = i2c_device_pm_resume,
};
@@ -843,6 +843,9 @@ int i2c_del_adapter(struct i2c_adapter *adap)
adap->dev.parent);
#endif
+ /* device name is gone after device_unregister */
+ dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
+
/* clean up the sysfs representation */
init_completion(&adap->dev_released);
device_unregister(&adap->dev);
@@ -855,8 +858,6 @@ int i2c_del_adapter(struct i2c_adapter *adap)
idr_remove(&i2c_adapter_idr, adap->nr);
mutex_unlock(&core_lock);
- dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
-
/* Clear the device structure in case this adapter is ever going to be
added again */
memset(&adap->dev, 0, sizeof(adap->dev));
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index dee6706038a..258c639571b 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -59,7 +59,8 @@ static void evdev_pass_event(struct evdev_client *client,
client->head &= EVDEV_BUFFER_SIZE - 1;
spin_unlock(&client->buffer_lock);
- kill_fasync(&client->fasync, SIGIO, POLL_IN);
+ if (event->type == EV_SYN)
+ kill_fasync(&client->fasync, SIGIO, POLL_IN);
}
/*
diff --git a/drivers/input/input.c b/drivers/input/input.c
index ab060710688..30b503b8d67 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -24,6 +24,7 @@
#include <linux/mutex.h>
#include <linux/rcupdate.h>
#include <linux/smp_lock.h>
+#include "input-compat.h"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("Input core");
@@ -764,6 +765,40 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han
return error;
}
+#ifdef CONFIG_COMPAT
+
+static int input_bits_to_string(char *buf, int buf_size,
+ unsigned long bits, bool skip_empty)
+{
+ int len = 0;
+
+ if (INPUT_COMPAT_TEST) {
+ u32 dword = bits >> 32;
+ if (dword || !skip_empty)
+ len += snprintf(buf, buf_size, "%x ", dword);
+
+ dword = bits & 0xffffffffUL;
+ if (dword || !skip_empty || len)
+ len += snprintf(buf + len, max(buf_size - len, 0),
+ "%x", dword);
+ } else {
+ if (bits || !skip_empty)
+ len += snprintf(buf, buf_size, "%lx", bits);
+ }
+
+ return len;
+}
+
+#else /* !CONFIG_COMPAT */
+
+static int input_bits_to_string(char *buf, int buf_size,
+ unsigned long bits, bool skip_empty)
+{
+ return bits || !skip_empty ?
+ snprintf(buf, buf_size, "%lx", bits) : 0;
+}
+
+#endif
#ifdef CONFIG_PROC_FS
@@ -832,14 +867,25 @@ static void input_seq_print_bitmap(struct seq_file *seq, const char *name,
unsigned long *bitmap, int max)
{
int i;
-
- for (i = BITS_TO_LONGS(max) - 1; i > 0; i--)
- if (bitmap[i])
- break;
+ bool skip_empty = true;
+ char buf[18];
seq_printf(seq, "B: %s=", name);
- for (; i >= 0; i--)
- seq_printf(seq, "%lx%s", bitmap[i], i > 0 ? " " : "");
+
+ for (i = BITS_TO_LONGS(max) - 1; i >= 0; i--) {
+ if (input_bits_to_string(buf, sizeof(buf),
+ bitmap[i], skip_empty)) {
+ skip_empty = false;
+ seq_printf(seq, "%s%s", buf, i > 0 ? " " : "");
+ }
+ }
+
+ /*
+ * If no output was produced print a single 0.
+ */
+ if (skip_empty)
+ seq_puts(seq, "0");
+
seq_putc(seq, '\n');
}
@@ -1128,14 +1174,23 @@ static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap,
{
int i;
int len = 0;
+ bool skip_empty = true;
+
+ for (i = BITS_TO_LONGS(max) - 1; i >= 0; i--) {
+ len += input_bits_to_string(buf + len, max(buf_size - len, 0),
+ bitmap[i], skip_empty);
+ if (len) {
+ skip_empty = false;
+ if (i > 0)
+ len += snprintf(buf + len, max(buf_size - len, 0), " ");
+ }
+ }
- for (i = BITS_TO_LONGS(max) - 1; i > 0; i--)
- if (bitmap[i])
- break;
-
- for (; i >= 0; i--)
- len += snprintf(buf + len, max(buf_size - len, 0),
- "%lx%s", bitmap[i], i > 0 ? " " : "");
+ /*
+ * If no output was produced print a single 0.
+ */
+ if (len == 0)
+ len = snprintf(buf, buf_size, "%d", 0);
if (add_cr)
len += snprintf(buf + len, max(buf_size - len, 0), "\n");
@@ -1150,7 +1205,8 @@ static ssize_t input_dev_show_cap_##bm(struct device *dev, \
{ \
struct input_dev *input_dev = to_input_dev(dev); \
int len = input_print_bitmap(buf, PAGE_SIZE, \
- input_dev->bm##bit, ev##_MAX, 1); \
+ input_dev->bm##bit, ev##_MAX, \
+ true); \
return min_t(int, len, PAGE_SIZE); \
} \
static DEVICE_ATTR(bm, S_IRUGO, input_dev_show_cap_##bm, NULL)
@@ -1214,7 +1270,7 @@ static int input_add_uevent_bm_var(struct kobj_uevent_env *env,
len = input_print_bitmap(&env->buf[env->buflen - 1],
sizeof(env->buf) - env->buflen,
- bitmap, max, 0);
+ bitmap, max, false);
if (len >= (sizeof(env->buf) - env->buflen))
return -ENOMEM;
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
index 67c207f5b1a..45ac70eae0a 100644
--- a/drivers/input/joystick/gf2k.c
+++ b/drivers/input/joystick/gf2k.c
@@ -277,7 +277,7 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv)
}
#ifdef RESET_WORKS
- if ((gf2k->id != (GB(19,2,0) | GB(15,3,2) | GB(12,3,5))) ||
+ if ((gf2k->id != (GB(19,2,0) | GB(15,3,2) | GB(12,3,5))) &&
(gf2k->id != (GB(31,2,0) | GB(27,3,2) | GB(24,3,5)))) {
err = -ENODEV;
goto fail2;
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 482cb1204e4..8a28fb7846d 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -446,7 +446,7 @@ static void xpad_irq_in(struct urb *urb)
}
exit:
- retval = usb_submit_urb (urb, GFP_ATOMIC);
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
err ("%s - usb_submit_urb failed with result %d",
__func__, retval);
@@ -571,7 +571,7 @@ static int xpad_play_effect(struct input_dev *dev, void *data,
xpad->odata[6] = 0x00;
xpad->odata[7] = 0x00;
xpad->irq_out->transfer_buffer_length = 8;
- usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+ usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
}
return 0;
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 1f5e2ce327d..7b4056292ea 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -225,8 +225,10 @@ struct atkbd {
struct delayed_work event_work;
unsigned long event_jiffies;
- struct mutex event_mutex;
unsigned long event_mask;
+
+ /* Serializes reconnect(), attr->set() and event work */
+ struct mutex mutex;
};
/*
@@ -577,7 +579,7 @@ static void atkbd_event_work(struct work_struct *work)
{
struct atkbd *atkbd = container_of(work, struct atkbd, event_work.work);
- mutex_lock(&atkbd->event_mutex);
+ mutex_lock(&atkbd->mutex);
if (!atkbd->enabled) {
/*
@@ -596,7 +598,7 @@ static void atkbd_event_work(struct work_struct *work)
atkbd_set_repeat_rate(atkbd);
}
- mutex_unlock(&atkbd->event_mutex);
+ mutex_unlock(&atkbd->mutex);
}
/*
@@ -612,7 +614,7 @@ static void atkbd_schedule_event_work(struct atkbd *atkbd, int event_bit)
atkbd->event_jiffies = jiffies;
set_bit(event_bit, &atkbd->event_mask);
- wmb();
+ mb();
schedule_delayed_work(&atkbd->event_work, delay);
}
@@ -849,13 +851,20 @@ static void atkbd_disconnect(struct serio *serio)
{
struct atkbd *atkbd = serio_get_drvdata(serio);
+ sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group);
+
atkbd_disable(atkbd);
- /* make sure we don't have a command in flight */
+ input_unregister_device(atkbd->dev);
+
+ /*
+ * Make sure we don't have a command in flight.
+ * Note that since atkbd->enabled is false event work will keep
+ * rescheduling itself until it gets canceled and will not try
+ * accessing freed input device or serio port.
+ */
cancel_delayed_work_sync(&atkbd->event_work);
- sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group);
- input_unregister_device(atkbd->dev);
serio_close(serio);
serio_set_drvdata(serio, NULL);
kfree(atkbd);
@@ -1087,7 +1096,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
atkbd->dev = dev;
ps2_init(&atkbd->ps2dev, serio);
INIT_DELAYED_WORK(&atkbd->event_work, atkbd_event_work);
- mutex_init(&atkbd->event_mutex);
+ mutex_init(&atkbd->mutex);
switch (serio->id.type) {
@@ -1160,19 +1169,23 @@ static int atkbd_reconnect(struct serio *serio)
{
struct atkbd *atkbd = serio_get_drvdata(serio);
struct serio_driver *drv = serio->drv;
+ int retval = -1;
if (!atkbd || !drv) {
printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n");
return -1;
}
+ mutex_lock(&atkbd->mutex);
+
atkbd_disable(atkbd);
if (atkbd->write) {
if (atkbd_probe(atkbd))
- return -1;
+ goto out;
+
if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra))
- return -1;
+ goto out;
atkbd_activate(atkbd);
@@ -1190,8 +1203,11 @@ static int atkbd_reconnect(struct serio *serio)
}
atkbd_enable(atkbd);
+ retval = 0;
- return 0;
+ out:
+ mutex_unlock(&atkbd->mutex);
+ return retval;
}
static struct serio_device_id atkbd_serio_ids[] = {
@@ -1235,47 +1251,28 @@ static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
ssize_t (*handler)(struct atkbd *, char *))
{
struct serio *serio = to_serio_port(dev);
- int retval;
-
- retval = serio_pin_driver(serio);
- if (retval)
- return retval;
-
- if (serio->drv != &atkbd_drv) {
- retval = -ENODEV;
- goto out;
- }
-
- retval = handler((struct atkbd *)serio_get_drvdata(serio), buf);
+ struct atkbd *atkbd = serio_get_drvdata(serio);
-out:
- serio_unpin_driver(serio);
- return retval;
+ return handler(atkbd, buf);
}
static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count,
ssize_t (*handler)(struct atkbd *, const char *, size_t))
{
struct serio *serio = to_serio_port(dev);
- struct atkbd *atkbd;
+ struct atkbd *atkbd = serio_get_drvdata(serio);
int retval;
- retval = serio_pin_driver(serio);
+ retval = mutex_lock_interruptible(&atkbd->mutex);
if (retval)
return retval;
- if (serio->drv != &atkbd_drv) {
- retval = -ENODEV;
- goto out;
- }
-
- atkbd = serio_get_drvdata(serio);
atkbd_disable(atkbd);
retval = handler(atkbd, buf, count);
atkbd_enable(atkbd);
-out:
- serio_unpin_driver(serio);
+ mutex_unlock(&atkbd->mutex);
+
return retval;
}
diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c
index 6e52d855f63..d410d7a52f1 100644
--- a/drivers/input/keyboard/davinci_keyscan.c
+++ b/drivers/input/keyboard/davinci_keyscan.c
@@ -174,6 +174,14 @@ static int __init davinci_ks_probe(struct platform_device *pdev)
struct davinci_ks_platform_data *pdata = pdev->dev.platform_data;
int error, i;
+ if (pdata->device_enable) {
+ error = pdata->device_enable(dev);
+ if (error < 0) {
+ dev_dbg(dev, "device enable function failed\n");
+ return error;
+ }
+ }
+
if (!pdata->keymap) {
dev_dbg(dev, "no keymap from pdata\n");
return -EINVAL;
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index 0d1d33468b4..4f8fe0886b2 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -139,6 +139,7 @@ struct tp_finger {
/* trackpad finger data size, empirically at least ten fingers */
#define SIZEOF_FINGER sizeof(struct tp_finger)
#define SIZEOF_ALL_FINGERS (16 * SIZEOF_FINGER)
+#define MAX_FINGER_ORIENTATION 16384
/* device-specific parameters */
struct bcm5974_param {
@@ -284,6 +285,26 @@ static void setup_events_to_report(struct input_dev *input_dev,
input_set_abs_params(input_dev, ABS_Y,
0, cfg->y.dim, cfg->y.fuzz, 0);
+ /* finger touch area */
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+ cfg->w.devmin, cfg->w.devmax, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR,
+ cfg->w.devmin, cfg->w.devmax, 0, 0);
+ /* finger approach area */
+ input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR,
+ cfg->w.devmin, cfg->w.devmax, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_WIDTH_MINOR,
+ cfg->w.devmin, cfg->w.devmax, 0, 0);
+ /* finger orientation */
+ input_set_abs_params(input_dev, ABS_MT_ORIENTATION,
+ -MAX_FINGER_ORIENTATION,
+ MAX_FINGER_ORIENTATION, 0, 0);
+ /* finger position */
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+ cfg->x.devmin, cfg->x.devmax, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+ cfg->y.devmin, cfg->y.devmax, 0, 0);
+
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
@@ -310,13 +331,29 @@ static int report_bt_state(struct bcm5974 *dev, int size)
return 0;
}
+static void report_finger_data(struct input_dev *input,
+ const struct bcm5974_config *cfg,
+ const struct tp_finger *f)
+{
+ input_report_abs(input, ABS_MT_TOUCH_MAJOR, raw2int(f->force_major));
+ input_report_abs(input, ABS_MT_TOUCH_MINOR, raw2int(f->force_minor));
+ input_report_abs(input, ABS_MT_WIDTH_MAJOR, raw2int(f->size_major));
+ input_report_abs(input, ABS_MT_WIDTH_MINOR, raw2int(f->size_minor));
+ input_report_abs(input, ABS_MT_ORIENTATION,
+ MAX_FINGER_ORIENTATION - raw2int(f->orientation));
+ input_report_abs(input, ABS_MT_POSITION_X, raw2int(f->abs_x));
+ input_report_abs(input, ABS_MT_POSITION_Y,
+ cfg->y.devmin + cfg->y.devmax - raw2int(f->abs_y));
+ input_mt_sync(input);
+}
+
/* report trackpad data as logical trackpad state */
static int report_tp_state(struct bcm5974 *dev, int size)
{
const struct bcm5974_config *c = &dev->cfg;
const struct tp_finger *f;
struct input_dev *input = dev->input;
- int raw_p, raw_w, raw_x, raw_y, raw_n;
+ int raw_p, raw_w, raw_x, raw_y, raw_n, i;
int ptest, origin, ibt = 0, nmin = 0, nmax = 0;
int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0;
@@ -329,6 +366,11 @@ static int report_tp_state(struct bcm5974 *dev, int size)
/* always track the first finger; when detached, start over */
if (raw_n) {
+
+ /* report raw trackpad data */
+ for (i = 0; i < raw_n; i++)
+ report_finger_data(input, c, &f[i]);
+
raw_p = raw2int(f->force_major);
raw_w = raw2int(f->size_major);
raw_x = raw2int(f->abs_x);
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 401ac6b6edd..9774bdfaa48 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -627,8 +627,15 @@ static int psmouse_extensions(struct psmouse *psmouse,
synaptics_hardware = true;
if (max_proto > PSMOUSE_IMEX) {
- if (!set_properties || synaptics_init(psmouse) == 0)
+/*
+ * Try activating protocol, but check if support is enabled first, since
+ * we try detecting Synaptics even when protocol is disabled.
+ */
+ if (synaptics_supported() &&
+ (!set_properties || synaptics_init(psmouse) == 0)) {
return PSMOUSE_SYNAPTICS;
+ }
+
/*
* Some Synaptics touchpads can emulate extended protocols (like IMPS/2).
* Unfortunately Logitech/Genius probes confuse some firmware versions so
@@ -683,19 +690,6 @@ static int psmouse_extensions(struct psmouse *psmouse,
max_proto = PSMOUSE_IMEX;
}
-/*
- * Try Finger Sensing Pad
- */
- if (max_proto > PSMOUSE_IMEX) {
- if (fsp_detect(psmouse, set_properties) == 0) {
- if (!set_properties || fsp_init(psmouse) == 0)
- return PSMOUSE_FSP;
-/*
- * Init failed, try basic relative protocols
- */
- max_proto = PSMOUSE_IMEX;
- }
- }
if (max_proto > PSMOUSE_IMEX) {
if (genius_detect(psmouse, set_properties) == 0)
@@ -712,6 +706,21 @@ static int psmouse_extensions(struct psmouse *psmouse,
}
/*
+ * Try Finger Sensing Pad. We do it here because its probe upsets
+ * Trackpoint devices (causing TP_READ_ID command to time out).
+ */
+ if (max_proto > PSMOUSE_IMEX) {
+ if (fsp_detect(psmouse, set_properties) == 0) {
+ if (!set_properties || fsp_init(psmouse) == 0)
+ return PSMOUSE_FSP;
+/*
+ * Init failed, try basic relative protocols
+ */
+ max_proto = PSMOUSE_IMEX;
+ }
+ }
+
+/*
* Reset to defaults in case the device got confused by extended
* protocol probes. Note that we follow up with full reset because
* some mice put themselves to sleep when they see PSMOUSE_RESET_DIS.
@@ -1450,24 +1459,10 @@ ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *de
struct serio *serio = to_serio_port(dev);
struct psmouse_attribute *attr = to_psmouse_attr(devattr);
struct psmouse *psmouse;
- int retval;
-
- retval = serio_pin_driver(serio);
- if (retval)
- return retval;
-
- if (serio->drv != &psmouse_drv) {
- retval = -ENODEV;
- goto out;
- }
psmouse = serio_get_drvdata(serio);
- retval = attr->show(psmouse, attr->data, buf);
-
-out:
- serio_unpin_driver(serio);
- return retval;
+ return attr->show(psmouse, attr->data, buf);
}
ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *devattr,
@@ -1478,18 +1473,9 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev
struct psmouse *psmouse, *parent = NULL;
int retval;
- retval = serio_pin_driver(serio);
- if (retval)
- return retval;
-
- if (serio->drv != &psmouse_drv) {
- retval = -ENODEV;
- goto out_unpin;
- }
-
retval = mutex_lock_interruptible(&psmouse_mutex);
if (retval)
- goto out_unpin;
+ goto out;
psmouse = serio_get_drvdata(serio);
@@ -1519,8 +1505,7 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev
out_unlock:
mutex_unlock(&psmouse_mutex);
- out_unpin:
- serio_unpin_driver(serio);
+ out:
return retval;
}
@@ -1582,9 +1567,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co
}
mutex_unlock(&psmouse_mutex);
- serio_unpin_driver(serio);
serio_unregister_child_port(serio);
- serio_pin_driver_uninterruptible(serio);
mutex_lock(&psmouse_mutex);
if (serio->drv != &psmouse_drv) {
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c
index 77b9fd0b3fb..81a6b81cb2f 100644
--- a/drivers/input/mouse/sentelic.c
+++ b/drivers/input/mouse/sentelic.c
@@ -2,7 +2,7 @@
* Finger Sensing Pad PS/2 mouse driver.
*
* Copyright (C) 2005-2007 Asia Vital Components Co., Ltd.
- * Copyright (C) 2005-2009 Tai-hwa Liang, Sentelic Corporation.
+ * Copyright (C) 2005-2010 Tai-hwa Liang, Sentelic Corporation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -658,9 +658,9 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
if (packet[3] & BIT(1))
button_status |= 0x0f; /* wheel up */
if (packet[3] & BIT(2))
- button_status |= BIT(5);/* horizontal left */
+ button_status |= BIT(4);/* horizontal left */
if (packet[3] & BIT(3))
- button_status |= BIT(4);/* horizontal right */
+ button_status |= BIT(5);/* horizontal right */
/* push back to packet queue */
if (button_status != 0)
packet[3] = button_status;
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 05689e73219..d3f5243fa09 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -743,6 +743,11 @@ int synaptics_init(struct psmouse *psmouse)
return -1;
}
+bool synaptics_supported(void)
+{
+ return true;
+}
+
#else /* CONFIG_MOUSE_PS2_SYNAPTICS */
void __init synaptics_module_init(void)
@@ -754,5 +759,10 @@ int synaptics_init(struct psmouse *psmouse)
return -ENOSYS;
}
+bool synaptics_supported(void)
+{
+ return false;
+}
+
#endif /* CONFIG_MOUSE_PS2_SYNAPTICS */
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index 838e7f2c9b3..f0f40a331dc 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -109,5 +109,6 @@ void synaptics_module_init(void);
int synaptics_detect(struct psmouse *psmouse, bool set_properties);
int synaptics_init(struct psmouse *psmouse);
void synaptics_reset(struct psmouse *psmouse);
+bool synaptics_supported(void);
#endif /* _SYNAPTICS_H */
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 64b688daf48..2a5982e532f 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -524,6 +524,13 @@ static const struct dmi_system_id __initconst i8042_dmi_laptop_table[] = {
*/
static const struct dmi_system_id __initconst i8042_dmi_dritek_table[] = {
{
+ /* Acer Aspire 5610 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
+ },
+ },
+ {
/* Acer Aspire 5630 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index 96faa799b82..f96feeb6b9c 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -660,7 +660,7 @@ static int smu_platform_probe(struct of_device* dev,
return 0;
}
-static struct of_device_id smu_platform_match[] =
+static const struct of_device_id smu_platform_match[] =
{
{
.type = "smu",
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index ea32c7e5a9a..454bc501df3 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -2211,7 +2211,7 @@ static int fcu_of_remove(struct of_device* dev)
return 0;
}
-static struct of_device_id fcu_match[] =
+static const struct of_device_id fcu_match[] =
{
{
.type = "fcu",
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
index 3fbe41b0ac0..ba48fd76396 100644
--- a/drivers/macintosh/therm_windtunnel.c
+++ b/drivers/macintosh/therm_windtunnel.c
@@ -457,7 +457,7 @@ therm_of_remove( struct of_device *dev )
return 0;
}
-static struct of_device_id therm_of_match[] = {{
+static const struct of_device_id therm_of_match[] = {{
.name = "fan",
.compatible = "adm1030"
}, {}
diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c
index bff7a535603..b521ed9d6e2 100644
--- a/drivers/media/IR/ir-keytable.c
+++ b/drivers/media/IR/ir-keytable.c
@@ -13,7 +13,7 @@
*/
-#include <linux/usb/input.h>
+#include <linux/input.h>
#include <media/ir-common.h>
#define IR_TAB_MIN_SIZE 32
diff --git a/drivers/media/common/tuners/tda8290.c b/drivers/media/common/tuners/tda8290.c
index c190b0dedee..2833137fa81 100644
--- a/drivers/media/common/tuners/tda8290.c
+++ b/drivers/media/common/tuners/tda8290.c
@@ -144,7 +144,8 @@ static void set_audio(struct dvb_frontend *fe,
}
if (params->mode == V4L2_TUNER_RADIO) {
- priv->tda8290_easy_mode = 0x01; /* Start with MN values */
+ /* Set TDA8295 to FM radio; Start TDA8290 with MN values */
+ priv->tda8290_easy_mode = (priv->ver & TDA8295) ? 0x80 : 0x01;
tuner_dbg("setting to radio FM\n");
} else {
tuner_dbg("setting tda829x to system %s\n", mode);
@@ -672,16 +673,19 @@ static int tda8290_probe(struct tuner_i2c_props *i2c_props)
static int tda8295_probe(struct tuner_i2c_props *i2c_props)
{
#define TDA8295_ID 0x8a
+#define TDA8295C2_ID 0x8b
unsigned char tda8295_id[] = { 0x2f, 0x00 };
/* detect tda8295 */
tuner_i2c_xfer_send(i2c_props, &tda8295_id[0], 1);
tuner_i2c_xfer_recv(i2c_props, &tda8295_id[1], 1);
- if (tda8295_id[1] == TDA8295_ID) {
+ if ((tda8295_id[1] & 0xfe) == TDA8295_ID) {
if (debug)
- printk(KERN_DEBUG "%s: tda8295 detected @ %d-%04x\n",
- __func__, i2c_adapter_id(i2c_props->adap),
+ printk(KERN_DEBUG "%s: %s detected @ %d-%04x\n",
+ __func__, (tda8295_id[1] == TDA8295_ID) ?
+ "tda8295c1" : "tda8295c2",
+ i2c_adapter_id(i2c_props->adap),
i2c_props->addr);
return 0;
}
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
index 35d0817126e..cf8f65f309d 100644
--- a/drivers/media/dvb/Kconfig
+++ b/drivers/media/dvb/Kconfig
@@ -72,6 +72,10 @@ comment "Supported Earthsoft PT1 Adapters"
depends on DVB_CORE && PCI && I2C
source "drivers/media/dvb/pt1/Kconfig"
+comment "Supported Mantis Adapters"
+ depends on DVB_CORE && PCI && I2C
+ source "drivers/media/dvb/mantis/Kconfig"
+
comment "Supported DVB Frontends"
depends on DVB_CORE
source "drivers/media/dvb/frontends/Kconfig"
diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile
index 16d262ddb45..c12922c3659 100644
--- a/drivers/media/dvb/Makefile
+++ b/drivers/media/dvb/Makefile
@@ -2,6 +2,18 @@
# Makefile for the kernel multimedia device drivers.
#
-obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/ pt1/
+obj-y := dvb-core/ \
+ frontends/ \
+ ttpci/ \
+ ttusb-dec/ \
+ ttusb-budget/ \
+ b2c2/ \
+ bt8xx/ \
+ dvb-usb/ \
+ pluto2/ \
+ siano/ \
+ dm1105/ \
+ pt1/ \
+ mantis/
obj-$(CONFIG_DVB_FIREDTV) += firewire/
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index a3b8b697349..cd7f9b7cbff 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -208,6 +208,14 @@ config DVB_DS3000
help
A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
+config DVB_MB86A16
+ tristate "Fujitsu MB86A16 based"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S/DSS Direct Conversion reveiver.
+ Say Y when you want to support this frontend.
+
comment "DVB-T (terrestrial) frontends"
depends on DVB_CORE
@@ -587,6 +595,17 @@ config DVB_ATBM8830
help
A DMB-TH tuner module. Say Y when you want to support this frontend.
+config DVB_TDA665x
+ tristate "TDA665x tuner"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ Support for tuner modules based on Philips TDA6650/TDA6651 chips.
+ Say Y when you want to support this chip.
+
+ Currently supported tuners:
+ * Panasonic ENV57H12D5 (ET-50DT)
+
comment "Tools to develop new frontends"
config DVB_DUMMY_FE
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 47575cc7b69..874e8ada4d1 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -64,6 +64,7 @@ obj-$(CONFIG_DVB_TDA10048) += tda10048.o
obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
+obj-$(CONFIG_DVB_TDA665x) += tda665x.o
obj-$(CONFIG_DVB_LGS8GXX) += lgs8gxx.o
obj-$(CONFIG_DVB_ATBM8830) += atbm8830.o
obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
@@ -80,3 +81,4 @@ obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
obj-$(CONFIG_DVB_ISL6423) += isl6423.o
obj-$(CONFIG_DVB_EC100) += ec100.o
obj-$(CONFIG_DVB_DS3000) += ds3000.o
+obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
diff --git a/drivers/media/dvb/frontends/dib8000.h b/drivers/media/dvb/frontends/dib8000.h
index d99619ae983..b1ee2079963 100644
--- a/drivers/media/dvb/frontends/dib8000.h
+++ b/drivers/media/dvb/frontends/dib8000.h
@@ -100,7 +100,7 @@ static inline int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_
static inline enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return CT_SHUTDOWN,
+ return CT_SHUTDOWN;
}
static inline void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
{
diff --git a/drivers/media/dvb/frontends/lgdt3305.h b/drivers/media/dvb/frontends/lgdt3305.h
index 4fa6e52d1fe..9cb11c9cae5 100644
--- a/drivers/media/dvb/frontends/lgdt3305.h
+++ b/drivers/media/dvb/frontends/lgdt3305.h
@@ -54,13 +54,13 @@ struct lgdt3305_config {
u16 usref_qam256; /* default: 0x2a80 */
/* disable i2c repeater - 0:repeater enabled 1:repeater disabled */
- int deny_i2c_rptr:1;
+ unsigned int deny_i2c_rptr:1;
/* spectral inversion - 0:disabled 1:enabled */
- int spectral_inversion:1;
+ unsigned int spectral_inversion:1;
/* use RF AGC loop - 0:disabled 1:enabled */
- int rf_agc_loop:1;
+ unsigned int rf_agc_loop:1;
enum lgdt3305_mpeg_mode mpeg_mode;
enum lgdt3305_tp_clock_edge tpclk_edge;
diff --git a/drivers/media/dvb/frontends/mb86a16.c b/drivers/media/dvb/frontends/mb86a16.c
new file mode 100644
index 00000000000..d05f7500e0c
--- /dev/null
+++ b/drivers/media/dvb/frontends/mb86a16.c
@@ -0,0 +1,1878 @@
+/*
+ Fujitsu MB86A16 DVB-S/DSS DC Receiver driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include "dvb_frontend.h"
+#include "mb86a16.h"
+#include "mb86a16_priv.h"
+
+unsigned int verbose = 5;
+module_param(verbose, int, 0644);
+
+#define ABS(x) ((x) < 0 ? (-x) : (x))
+
+struct mb86a16_state {
+ struct i2c_adapter *i2c_adap;
+ const struct mb86a16_config *config;
+ struct dvb_frontend frontend;
+
+ /* tuning parameters */
+ int frequency;
+ int srate;
+
+ /* Internal stuff */
+ int master_clk;
+ int deci;
+ int csel;
+ int rsel;
+};
+
+#define MB86A16_ERROR 0
+#define MB86A16_NOTICE 1
+#define MB86A16_INFO 2
+#define MB86A16_DEBUG 3
+
+#define dprintk(x, y, z, format, arg...) do { \
+ if (z) { \
+ if ((x > MB86A16_ERROR) && (x > y)) \
+ printk(KERN_ERR "%s: " format "\n", __func__, ##arg); \
+ else if ((x > MB86A16_NOTICE) && (x > y)) \
+ printk(KERN_NOTICE "%s: " format "\n", __func__, ##arg); \
+ else if ((x > MB86A16_INFO) && (x > y)) \
+ printk(KERN_INFO "%s: " format "\n", __func__, ##arg); \
+ else if ((x > MB86A16_DEBUG) && (x > y)) \
+ printk(KERN_DEBUG "%s: " format "\n", __func__, ##arg); \
+ } else { \
+ if (x > y) \
+ printk(format, ##arg); \
+ } \
+} while (0)
+
+#define TRACE_IN dprintk(verbose, MB86A16_DEBUG, 1, "-->()")
+#define TRACE_OUT dprintk(verbose, MB86A16_DEBUG, 1, "()-->")
+
+static int mb86a16_write(struct mb86a16_state *state, u8 reg, u8 val)
+{
+ int ret;
+ u8 buf[] = { reg, val };
+
+ struct i2c_msg msg = {
+ .addr = state->config->demod_address,
+ .flags = 0,
+ .buf = buf,
+ .len = 2
+ };
+
+ dprintk(verbose, MB86A16_DEBUG, 1,
+ "writing to [0x%02x],Reg[0x%02x],Data[0x%02x]",
+ state->config->demod_address, buf[0], buf[1]);
+
+ ret = i2c_transfer(state->i2c_adap, &msg, 1);
+
+ return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int mb86a16_read(struct mb86a16_state *state, u8 reg, u8 *val)
+{
+ int ret;
+ u8 b0[] = { reg };
+ u8 b1[] = { 0 };
+
+ struct i2c_msg msg[] = {
+ {
+ .addr = state->config->demod_address,
+ .flags = 0,
+ .buf = b0,
+ .len = 1
+ }, {
+ .addr = state->config->demod_address,
+ .flags = I2C_M_RD,
+ .buf = b1,
+ .len = 1
+ }
+ };
+ ret = i2c_transfer(state->i2c_adap, msg, 2);
+ if (ret != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "read error(reg=0x%02x, ret=0x%i)",
+ reg, ret);
+
+ return -EREMOTEIO;
+ }
+ *val = b1[0];
+
+ return ret;
+}
+
+static int CNTM_set(struct mb86a16_state *state,
+ unsigned char timint1,
+ unsigned char timint2,
+ unsigned char cnext)
+{
+ unsigned char val;
+
+ val = (timint1 << 4) | (timint2 << 2) | cnext;
+ if (mb86a16_write(state, MB86A16_CNTMR, val) < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int smrt_set(struct mb86a16_state *state, int rate)
+{
+ int tmp ;
+ int m ;
+ unsigned char STOFS0, STOFS1;
+
+ m = 1 << state->deci;
+ tmp = (8192 * state->master_clk - 2 * m * rate * 8192 + state->master_clk / 2) / state->master_clk;
+
+ STOFS0 = tmp & 0x0ff;
+ STOFS1 = (tmp & 0xf00) >> 8;
+
+ if (mb86a16_write(state, MB86A16_SRATE1, (state->deci << 2) |
+ (state->csel << 1) |
+ state->rsel) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_SRATE2, STOFS0) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_SRATE3, STOFS1) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -1;
+}
+
+static int srst(struct mb86a16_state *state)
+{
+ if (mb86a16_write(state, MB86A16_RESET, 0x04) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+
+}
+
+static int afcex_data_set(struct mb86a16_state *state,
+ unsigned char AFCEX_L,
+ unsigned char AFCEX_H)
+{
+ if (mb86a16_write(state, MB86A16_AFCEXL, AFCEX_L) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_AFCEXH, AFCEX_H) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+
+ return -1;
+}
+
+static int afcofs_data_set(struct mb86a16_state *state,
+ unsigned char AFCEX_L,
+ unsigned char AFCEX_H)
+{
+ if (mb86a16_write(state, 0x58, AFCEX_L) < 0)
+ goto err;
+ if (mb86a16_write(state, 0x59, AFCEX_H) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int stlp_set(struct mb86a16_state *state,
+ unsigned char STRAS,
+ unsigned char STRBS)
+{
+ if (mb86a16_write(state, MB86A16_STRFILTCOEF1, (STRBS << 3) | (STRAS)) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int Vi_set(struct mb86a16_state *state, unsigned char ETH, unsigned char VIA)
+{
+ if (mb86a16_write(state, MB86A16_VISET2, 0x04) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_VISET3, 0xf5) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int initial_set(struct mb86a16_state *state)
+{
+ if (stlp_set(state, 5, 7))
+ goto err;
+
+ udelay(100);
+ if (afcex_data_set(state, 0, 0))
+ goto err;
+
+ udelay(100);
+ if (afcofs_data_set(state, 0, 0))
+ goto err;
+
+ udelay(100);
+ if (mb86a16_write(state, MB86A16_CRLFILTCOEF1, 0x16) < 0)
+ goto err;
+ if (mb86a16_write(state, 0x2f, 0x21) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_VIMAG, 0x38) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_FAGCS1, 0x00) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_FAGCS2, 0x1c) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_FAGCS3, 0x20) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_FAGCS4, 0x1e) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_FAGCS5, 0x23) < 0)
+ goto err;
+ if (mb86a16_write(state, 0x54, 0xff) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_TSOUT, 0x00) < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int S01T_set(struct mb86a16_state *state,
+ unsigned char s1t,
+ unsigned s0t)
+{
+ if (mb86a16_write(state, 0x33, (s1t << 3) | s0t) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+
+static int EN_set(struct mb86a16_state *state,
+ int cren,
+ int afcen)
+{
+ unsigned char val;
+
+ val = 0x7a | (cren << 7) | (afcen << 2);
+ if (mb86a16_write(state, 0x49, val) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int AFCEXEN_set(struct mb86a16_state *state,
+ int afcexen,
+ int smrt)
+{
+ unsigned char AFCA ;
+
+ if (smrt > 18875)
+ AFCA = 4;
+ else if (smrt > 9375)
+ AFCA = 3;
+ else if (smrt > 2250)
+ AFCA = 2;
+ else
+ AFCA = 1;
+
+ if (mb86a16_write(state, 0x2a, 0x02 | (afcexen << 5) | (AFCA << 2)) < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int DAGC_data_set(struct mb86a16_state *state,
+ unsigned char DAGCA,
+ unsigned char DAGCW)
+{
+ if (mb86a16_write(state, 0x2d, (DAGCA << 3) | DAGCW) < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static void smrt_info_get(struct mb86a16_state *state, int rate)
+{
+ if (rate >= 37501) {
+ state->deci = 0; state->csel = 0; state->rsel = 0;
+ } else if (rate >= 30001) {
+ state->deci = 0; state->csel = 0; state->rsel = 1;
+ } else if (rate >= 26251) {
+ state->deci = 0; state->csel = 1; state->rsel = 0;
+ } else if (rate >= 22501) {
+ state->deci = 0; state->csel = 1; state->rsel = 1;
+ } else if (rate >= 18751) {
+ state->deci = 1; state->csel = 0; state->rsel = 0;
+ } else if (rate >= 15001) {
+ state->deci = 1; state->csel = 0; state->rsel = 1;
+ } else if (rate >= 13126) {
+ state->deci = 1; state->csel = 1; state->rsel = 0;
+ } else if (rate >= 11251) {
+ state->deci = 1; state->csel = 1; state->rsel = 1;
+ } else if (rate >= 9376) {
+ state->deci = 2; state->csel = 0; state->rsel = 0;
+ } else if (rate >= 7501) {
+ state->deci = 2; state->csel = 0; state->rsel = 1;
+ } else if (rate >= 6563) {
+ state->deci = 2; state->csel = 1; state->rsel = 0;
+ } else if (rate >= 5626) {
+ state->deci = 2; state->csel = 1; state->rsel = 1;
+ } else if (rate >= 4688) {
+ state->deci = 3; state->csel = 0; state->rsel = 0;
+ } else if (rate >= 3751) {
+ state->deci = 3; state->csel = 0; state->rsel = 1;
+ } else if (rate >= 3282) {
+ state->deci = 3; state->csel = 1; state->rsel = 0;
+ } else if (rate >= 2814) {
+ state->deci = 3; state->csel = 1; state->rsel = 1;
+ } else if (rate >= 2344) {
+ state->deci = 4; state->csel = 0; state->rsel = 0;
+ } else if (rate >= 1876) {
+ state->deci = 4; state->csel = 0; state->rsel = 1;
+ } else if (rate >= 1641) {
+ state->deci = 4; state->csel = 1; state->rsel = 0;
+ } else if (rate >= 1407) {
+ state->deci = 4; state->csel = 1; state->rsel = 1;
+ } else if (rate >= 1172) {
+ state->deci = 5; state->csel = 0; state->rsel = 0;
+ } else if (rate >= 939) {
+ state->deci = 5; state->csel = 0; state->rsel = 1;
+ } else if (rate >= 821) {
+ state->deci = 5; state->csel = 1; state->rsel = 0;
+ } else {
+ state->deci = 5; state->csel = 1; state->rsel = 1;
+ }
+
+ if (state->csel == 0)
+ state->master_clk = 92000;
+ else
+ state->master_clk = 61333;
+
+}
+
+static int signal_det(struct mb86a16_state *state,
+ int smrt,
+ unsigned char *SIG)
+{
+
+ int ret ;
+ int smrtd ;
+ int wait_sym ;
+
+ u32 wait_t;
+ unsigned char S[3] ;
+ int i ;
+
+ if (*SIG > 45) {
+ if (CNTM_set(state, 2, 1, 2) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error");
+ return -1;
+ }
+ wait_sym = 40000;
+ } else {
+ if (CNTM_set(state, 3, 1, 2) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error");
+ return -1;
+ }
+ wait_sym = 80000;
+ }
+ for (i = 0; i < 3; i++) {
+ if (i == 0)
+ smrtd = smrt * 98 / 100;
+ else if (i == 1)
+ smrtd = smrt;
+ else
+ smrtd = smrt * 102 / 100;
+ smrt_info_get(state, smrtd);
+ smrt_set(state, smrtd);
+ srst(state);
+ wait_t = (wait_sym + 99 * smrtd / 100) / smrtd;
+ if (wait_t == 0)
+ wait_t = 1;
+ msleep_interruptible(10);
+ if (mb86a16_read(state, 0x37, &(S[i])) != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+ }
+ if ((S[1] > S[0] * 112 / 100) &&
+ (S[1] > S[2] * 112 / 100)) {
+
+ ret = 1;
+ } else {
+ ret = 0;
+ }
+ *SIG = S[1];
+
+ if (CNTM_set(state, 0, 1, 2) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error");
+ return -1;
+ }
+
+ return ret;
+}
+
+static int rf_val_set(struct mb86a16_state *state,
+ int f,
+ int smrt,
+ unsigned char R)
+{
+ unsigned char C, F, B;
+ int M;
+ unsigned char rf_val[5];
+ int ack = -1;
+
+ if (smrt > 37750)
+ C = 1;
+ else if (smrt > 18875)
+ C = 2;
+ else if (smrt > 5500)
+ C = 3;
+ else
+ C = 4;
+
+ if (smrt > 30500)
+ F = 3;
+ else if (smrt > 9375)
+ F = 1;
+ else if (smrt > 4625)
+ F = 0;
+ else
+ F = 2;
+
+ if (f < 1060)
+ B = 0;
+ else if (f < 1175)
+ B = 1;
+ else if (f < 1305)
+ B = 2;
+ else if (f < 1435)
+ B = 3;
+ else if (f < 1570)
+ B = 4;
+ else if (f < 1715)
+ B = 5;
+ else if (f < 1845)
+ B = 6;
+ else if (f < 1980)
+ B = 7;
+ else if (f < 2080)
+ B = 8;
+ else
+ B = 9;
+
+ M = f * (1 << R) / 2;
+
+ rf_val[0] = 0x01 | (C << 3) | (F << 1);
+ rf_val[1] = (R << 5) | ((M & 0x1f000) >> 12);
+ rf_val[2] = (M & 0x00ff0) >> 4;
+ rf_val[3] = ((M & 0x0000f) << 4) | B;
+
+ /* Frequency Set */
+ if (mb86a16_write(state, 0x21, rf_val[0]) < 0)
+ ack = 0;
+ if (mb86a16_write(state, 0x22, rf_val[1]) < 0)
+ ack = 0;
+ if (mb86a16_write(state, 0x23, rf_val[2]) < 0)
+ ack = 0;
+ if (mb86a16_write(state, 0x24, rf_val[3]) < 0)
+ ack = 0;
+ if (mb86a16_write(state, 0x25, 0x01) < 0)
+ ack = 0;
+ if (ack == 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "RF Setup - I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int afcerr_chk(struct mb86a16_state *state)
+{
+ unsigned char AFCM_L, AFCM_H ;
+ int AFCM ;
+ int afcm, afcerr ;
+
+ if (mb86a16_read(state, 0x0e, &AFCM_L) != 2)
+ goto err;
+ if (mb86a16_read(state, 0x0f, &AFCM_H) != 2)
+ goto err;
+
+ AFCM = (AFCM_H << 8) + AFCM_L;
+
+ if (AFCM > 2048)
+ afcm = AFCM - 4096;
+ else
+ afcm = AFCM;
+ afcerr = afcm * state->master_clk / 8192;
+
+ return afcerr;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int dagcm_val_get(struct mb86a16_state *state)
+{
+ int DAGCM;
+ unsigned char DAGCM_H, DAGCM_L;
+
+ if (mb86a16_read(state, 0x45, &DAGCM_L) != 2)
+ goto err;
+ if (mb86a16_read(state, 0x46, &DAGCM_H) != 2)
+ goto err;
+
+ DAGCM = (DAGCM_H << 8) + DAGCM_L;
+
+ return DAGCM;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int mb86a16_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ u8 stat, stat2;
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ *status = 0;
+
+ if (mb86a16_read(state, MB86A16_SIG1, &stat) != 2)
+ goto err;
+ if (mb86a16_read(state, MB86A16_SIG2, &stat2) != 2)
+ goto err;
+ if ((stat > 25) && (stat2 > 25))
+ *status |= FE_HAS_SIGNAL;
+ if ((stat > 45) && (stat2 > 45))
+ *status |= FE_HAS_CARRIER;
+
+ if (mb86a16_read(state, MB86A16_STATUS, &stat) != 2)
+ goto err;
+
+ if (stat & 0x01)
+ *status |= FE_HAS_SYNC;
+ if (stat & 0x01)
+ *status |= FE_HAS_VITERBI;
+
+ if (mb86a16_read(state, MB86A16_FRAMESYNC, &stat) != 2)
+ goto err;
+
+ if ((stat & 0x0f) && (*status & FE_HAS_VITERBI))
+ *status |= FE_HAS_LOCK;
+
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int sync_chk(struct mb86a16_state *state,
+ unsigned char *VIRM)
+{
+ unsigned char val;
+ int sync;
+
+ if (mb86a16_read(state, 0x0d, &val) != 2)
+ goto err;
+
+ dprintk(verbose, MB86A16_INFO, 1, "Status = %02x,", val);
+ sync = val & 0x01;
+ *VIRM = (val & 0x1c) >> 2;
+
+ return sync;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+
+}
+
+static int freqerr_chk(struct mb86a16_state *state,
+ int fTP,
+ int smrt,
+ int unit)
+{
+ unsigned char CRM, AFCML, AFCMH;
+ unsigned char temp1, temp2, temp3;
+ int crm, afcm, AFCM;
+ int crrerr, afcerr; /* kHz */
+ int frqerr; /* MHz */
+ int afcen, afcexen = 0;
+ int R, M, fOSC, fOSC_OFS;
+
+ if (mb86a16_read(state, 0x43, &CRM) != 2)
+ goto err;
+
+ if (CRM > 127)
+ crm = CRM - 256;
+ else
+ crm = CRM;
+
+ crrerr = smrt * crm / 256;
+ if (mb86a16_read(state, 0x49, &temp1) != 2)
+ goto err;
+
+ afcen = (temp1 & 0x04) >> 2;
+ if (afcen == 0) {
+ if (mb86a16_read(state, 0x2a, &temp1) != 2)
+ goto err;
+ afcexen = (temp1 & 0x20) >> 5;
+ }
+
+ if (afcen == 1) {
+ if (mb86a16_read(state, 0x0e, &AFCML) != 2)
+ goto err;
+ if (mb86a16_read(state, 0x0f, &AFCMH) != 2)
+ goto err;
+ } else if (afcexen == 1) {
+ if (mb86a16_read(state, 0x2b, &AFCML) != 2)
+ goto err;
+ if (mb86a16_read(state, 0x2c, &AFCMH) != 2)
+ goto err;
+ }
+ if ((afcen == 1) || (afcexen == 1)) {
+ smrt_info_get(state, smrt);
+ AFCM = ((AFCMH & 0x01) << 8) + AFCML;
+ if (AFCM > 255)
+ afcm = AFCM - 512;
+ else
+ afcm = AFCM;
+
+ afcerr = afcm * state->master_clk / 8192;
+ } else
+ afcerr = 0;
+
+ if (mb86a16_read(state, 0x22, &temp1) != 2)
+ goto err;
+ if (mb86a16_read(state, 0x23, &temp2) != 2)
+ goto err;
+ if (mb86a16_read(state, 0x24, &temp3) != 2)
+ goto err;
+
+ R = (temp1 & 0xe0) >> 5;
+ M = ((temp1 & 0x1f) << 12) + (temp2 << 4) + (temp3 >> 4);
+ if (R == 0)
+ fOSC = 2 * M;
+ else
+ fOSC = M;
+
+ fOSC_OFS = fOSC - fTP;
+
+ if (unit == 0) { /* MHz */
+ if (crrerr + afcerr + fOSC_OFS * 1000 >= 0)
+ frqerr = (crrerr + afcerr + fOSC_OFS * 1000 + 500) / 1000;
+ else
+ frqerr = (crrerr + afcerr + fOSC_OFS * 1000 - 500) / 1000;
+ } else { /* kHz */
+ frqerr = crrerr + afcerr + fOSC_OFS * 1000;
+ }
+
+ return frqerr;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static unsigned char vco_dev_get(struct mb86a16_state *state, int smrt)
+{
+ unsigned char R;
+
+ if (smrt > 9375)
+ R = 0;
+ else
+ R = 1;
+
+ return R;
+}
+
+static void swp_info_get(struct mb86a16_state *state,
+ int fOSC_start,
+ int smrt,
+ int v, int R,
+ int swp_ofs,
+ int *fOSC,
+ int *afcex_freq,
+ unsigned char *AFCEX_L,
+ unsigned char *AFCEX_H)
+{
+ int AFCEX ;
+ int crnt_swp_freq ;
+
+ crnt_swp_freq = fOSC_start * 1000 + v * swp_ofs;
+
+ if (R == 0)
+ *fOSC = (crnt_swp_freq + 1000) / 2000 * 2;
+ else
+ *fOSC = (crnt_swp_freq + 500) / 1000;
+
+ if (*fOSC >= crnt_swp_freq)
+ *afcex_freq = *fOSC * 1000 - crnt_swp_freq;
+ else
+ *afcex_freq = crnt_swp_freq - *fOSC * 1000;
+
+ AFCEX = *afcex_freq * 8192 / state->master_clk;
+ *AFCEX_L = AFCEX & 0x00ff;
+ *AFCEX_H = (AFCEX & 0x0f00) >> 8;
+}
+
+
+static int swp_freq_calcuation(struct mb86a16_state *state, int i, int v, int *V, int vmax, int vmin,
+ int SIGMIN, int fOSC, int afcex_freq, int swp_ofs, unsigned char *SIG1)
+{
+ int swp_freq ;
+
+ if ((i % 2 == 1) && (v <= vmax)) {
+ /* positive v (case 1) */
+ if ((v - 1 == vmin) &&
+ (*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v - 1) >= 0) &&
+ (*(V + 30 + v - 1) > *(V + 30 + v)) &&
+ (*(V + 30 + v - 1) > SIGMIN)) {
+
+ swp_freq = fOSC * 1000 + afcex_freq - swp_ofs;
+ *SIG1 = *(V + 30 + v - 1);
+ } else if ((v == vmax) &&
+ (*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v - 1) >= 0) &&
+ (*(V + 30 + v) > *(V + 30 + v - 1)) &&
+ (*(V + 30 + v) > SIGMIN)) {
+ /* (case 2) */
+ swp_freq = fOSC * 1000 + afcex_freq;
+ *SIG1 = *(V + 30 + v);
+ } else if ((*(V + 30 + v) > 0) &&
+ (*(V + 30 + v - 1) > 0) &&
+ (*(V + 30 + v - 2) > 0) &&
+ (*(V + 30 + v - 3) > 0) &&
+ (*(V + 30 + v - 1) > *(V + 30 + v)) &&
+ (*(V + 30 + v - 2) > *(V + 30 + v - 3)) &&
+ ((*(V + 30 + v - 1) > SIGMIN) ||
+ (*(V + 30 + v - 2) > SIGMIN))) {
+ /* (case 3) */
+ if (*(V + 30 + v - 1) >= *(V + 30 + v - 2)) {
+ swp_freq = fOSC * 1000 + afcex_freq - swp_ofs;
+ *SIG1 = *(V + 30 + v - 1);
+ } else {
+ swp_freq = fOSC * 1000 + afcex_freq - swp_ofs * 2;
+ *SIG1 = *(V + 30 + v - 2);
+ }
+ } else if ((v == vmax) &&
+ (*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v - 1) >= 0) &&
+ (*(V + 30 + v - 2) >= 0) &&
+ (*(V + 30 + v) > *(V + 30 + v - 2)) &&
+ (*(V + 30 + v - 1) > *(V + 30 + v - 2)) &&
+ ((*(V + 30 + v) > SIGMIN) ||
+ (*(V + 30 + v - 1) > SIGMIN))) {
+ /* (case 4) */
+ if (*(V + 30 + v) >= *(V + 30 + v - 1)) {
+ swp_freq = fOSC * 1000 + afcex_freq;
+ *SIG1 = *(V + 30 + v);
+ } else {
+ swp_freq = fOSC * 1000 + afcex_freq - swp_ofs;
+ *SIG1 = *(V + 30 + v - 1);
+ }
+ } else {
+ swp_freq = -1 ;
+ }
+ } else if ((i % 2 == 0) && (v >= vmin)) {
+ /* Negative v (case 1) */
+ if ((*(V + 30 + v) > 0) &&
+ (*(V + 30 + v + 1) > 0) &&
+ (*(V + 30 + v + 2) > 0) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v)) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v + 2)) &&
+ (*(V + 30 + v + 1) > SIGMIN)) {
+
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+ *SIG1 = *(V + 30 + v + 1);
+ } else if ((v + 1 == vmax) &&
+ (*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v + 1) >= 0) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v)) &&
+ (*(V + 30 + v + 1) > SIGMIN)) {
+ /* (case 2) */
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+ *SIG1 = *(V + 30 + v);
+ } else if ((v == vmin) &&
+ (*(V + 30 + v) > 0) &&
+ (*(V + 30 + v + 1) > 0) &&
+ (*(V + 30 + v + 2) > 0) &&
+ (*(V + 30 + v) > *(V + 30 + v + 1)) &&
+ (*(V + 30 + v) > *(V + 30 + v + 2)) &&
+ (*(V + 30 + v) > SIGMIN)) {
+ /* (case 3) */
+ swp_freq = fOSC * 1000 + afcex_freq;
+ *SIG1 = *(V + 30 + v);
+ } else if ((*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v + 1) >= 0) &&
+ (*(V + 30 + v + 2) >= 0) &&
+ (*(V + 30 + v + 3) >= 0) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v)) &&
+ (*(V + 30 + v + 2) > *(V + 30 + v + 3)) &&
+ ((*(V + 30 + v + 1) > SIGMIN) ||
+ (*(V + 30 + v + 2) > SIGMIN))) {
+ /* (case 4) */
+ if (*(V + 30 + v + 1) >= *(V + 30 + v + 2)) {
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+ *SIG1 = *(V + 30 + v + 1);
+ } else {
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs * 2;
+ *SIG1 = *(V + 30 + v + 2);
+ }
+ } else if ((*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v + 1) >= 0) &&
+ (*(V + 30 + v + 2) >= 0) &&
+ (*(V + 30 + v + 3) >= 0) &&
+ (*(V + 30 + v) > *(V + 30 + v + 2)) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v + 2)) &&
+ (*(V + 30 + v) > *(V + 30 + v + 3)) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v + 3)) &&
+ ((*(V + 30 + v) > SIGMIN) ||
+ (*(V + 30 + v + 1) > SIGMIN))) {
+ /* (case 5) */
+ if (*(V + 30 + v) >= *(V + 30 + v + 1)) {
+ swp_freq = fOSC * 1000 + afcex_freq;
+ *SIG1 = *(V + 30 + v);
+ } else {
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+ *SIG1 = *(V + 30 + v + 1);
+ }
+ } else if ((v + 2 == vmin) &&
+ (*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v + 1) >= 0) &&
+ (*(V + 30 + v + 2) >= 0) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v)) &&
+ (*(V + 30 + v + 2) > *(V + 30 + v)) &&
+ ((*(V + 30 + v + 1) > SIGMIN) ||
+ (*(V + 30 + v + 2) > SIGMIN))) {
+ /* (case 6) */
+ if (*(V + 30 + v + 1) >= *(V + 30 + v + 2)) {
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+ *SIG1 = *(V + 30 + v + 1);
+ } else {
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs * 2;
+ *SIG1 = *(V + 30 + v + 2);
+ }
+ } else if ((vmax == 0) && (vmin == 0) && (*(V + 30 + v) > SIGMIN)) {
+ swp_freq = fOSC * 1000;
+ *SIG1 = *(V + 30 + v);
+ } else
+ swp_freq = -1;
+ } else
+ swp_freq = -1;
+
+ return swp_freq;
+}
+
+static void swp_info_get2(struct mb86a16_state *state,
+ int smrt,
+ int R,
+ int swp_freq,
+ int *afcex_freq,
+ int *fOSC,
+ unsigned char *AFCEX_L,
+ unsigned char *AFCEX_H)
+{
+ int AFCEX ;
+
+ if (R == 0)
+ *fOSC = (swp_freq + 1000) / 2000 * 2;
+ else
+ *fOSC = (swp_freq + 500) / 1000;
+
+ if (*fOSC >= swp_freq)
+ *afcex_freq = *fOSC * 1000 - swp_freq;
+ else
+ *afcex_freq = swp_freq - *fOSC * 1000;
+
+ AFCEX = *afcex_freq * 8192 / state->master_clk;
+ *AFCEX_L = AFCEX & 0x00ff;
+ *AFCEX_H = (AFCEX & 0x0f00) >> 8;
+}
+
+static void afcex_info_get(struct mb86a16_state *state,
+ int afcex_freq,
+ unsigned char *AFCEX_L,
+ unsigned char *AFCEX_H)
+{
+ int AFCEX ;
+
+ AFCEX = afcex_freq * 8192 / state->master_clk;
+ *AFCEX_L = AFCEX & 0x00ff;
+ *AFCEX_H = (AFCEX & 0x0f00) >> 8;
+}
+
+static int SEQ_set(struct mb86a16_state *state, unsigned char loop)
+{
+ /* SLOCK0 = 0 */
+ if (mb86a16_write(state, 0x32, 0x02 | (loop << 2)) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int iq_vt_set(struct mb86a16_state *state, unsigned char IQINV)
+{
+ /* Viterbi Rate, IQ Settings */
+ if (mb86a16_write(state, 0x06, 0xdf | (IQINV << 5)) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int FEC_srst(struct mb86a16_state *state)
+{
+ if (mb86a16_write(state, MB86A16_RESET, 0x02) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int S2T_set(struct mb86a16_state *state, unsigned char S2T)
+{
+ if (mb86a16_write(state, 0x34, 0x70 | S2T) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int S45T_set(struct mb86a16_state *state, unsigned char S4T, unsigned char S5T)
+{
+ if (mb86a16_write(state, 0x35, 0x00 | (S5T << 4) | S4T) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+
+static int mb86a16_set_fe(struct mb86a16_state *state)
+{
+ u8 agcval, cnmval;
+
+ int i, j;
+ int fOSC = 0;
+ int fOSC_start = 0;
+ int wait_t;
+ int fcp;
+ int swp_ofs;
+ int V[60];
+ u8 SIG1MIN;
+
+ unsigned char CREN, AFCEN, AFCEXEN;
+ unsigned char SIG1;
+ unsigned char TIMINT1, TIMINT2, TIMEXT;
+ unsigned char S0T, S1T;
+ unsigned char S2T;
+/* unsigned char S2T, S3T; */
+ unsigned char S4T, S5T;
+ unsigned char AFCEX_L, AFCEX_H;
+ unsigned char R;
+ unsigned char VIRM;
+ unsigned char ETH, VIA;
+ unsigned char junk;
+
+ int loop;
+ int ftemp;
+ int v, vmax, vmin;
+ int vmax_his, vmin_his;
+ int swp_freq, prev_swp_freq[20];
+ int prev_freq_num;
+ int signal_dupl;
+ int afcex_freq;
+ int signal;
+ int afcerr;
+ int temp_freq, delta_freq;
+ int dagcm[4];
+ int smrt_d;
+/* int freq_err; */
+ int n;
+ int ret = -1;
+ int sync;
+
+ dprintk(verbose, MB86A16_INFO, 1, "freq=%d Mhz, symbrt=%d Ksps", state->frequency, state->srate);
+
+ fcp = 3000;
+ swp_ofs = state->srate / 4;
+
+ for (i = 0; i < 60; i++)
+ V[i] = -1;
+
+ for (i = 0; i < 20; i++)
+ prev_swp_freq[i] = 0;
+
+ SIG1MIN = 25;
+
+ for (n = 0; ((n < 3) && (ret == -1)); n++) {
+ SEQ_set(state, 0);
+ iq_vt_set(state, 0);
+
+ CREN = 0;
+ AFCEN = 0;
+ AFCEXEN = 1;
+ TIMINT1 = 0;
+ TIMINT2 = 1;
+ TIMEXT = 2;
+ S1T = 0;
+ S0T = 0;
+
+ if (initial_set(state) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "initial set failed");
+ return -1;
+ }
+ if (DAGC_data_set(state, 3, 2) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error");
+ return -1;
+ }
+ if (EN_set(state, CREN, AFCEN) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "EN set error");
+ return -1; /* (0, 0) */
+ }
+ if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
+ return -1; /* (1, smrt) = (1, symbolrate) */
+ }
+ if (CNTM_set(state, TIMINT1, TIMINT2, TIMEXT) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "CNTM set error");
+ return -1; /* (0, 1, 2) */
+ }
+ if (S01T_set(state, S1T, S0T) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "S01T set error");
+ return -1; /* (0, 0) */
+ }
+ smrt_info_get(state, state->srate);
+ if (smrt_set(state, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "smrt info get error");
+ return -1;
+ }
+
+ R = vco_dev_get(state, state->srate);
+ if (R == 1)
+ fOSC_start = state->frequency;
+
+ else if (R == 0) {
+ if (state->frequency % 2 == 0) {
+ fOSC_start = state->frequency;
+ } else {
+ fOSC_start = state->frequency + 1;
+ if (fOSC_start > 2150)
+ fOSC_start = state->frequency - 1;
+ }
+ }
+ loop = 1;
+ ftemp = fOSC_start * 1000;
+ vmax = 0 ;
+ while (loop == 1) {
+ ftemp = ftemp + swp_ofs;
+ vmax++;
+
+ /* Upper bound */
+ if (ftemp > 2150000) {
+ loop = 0;
+ vmax--;
+ } else {
+ if ((ftemp == 2150000) ||
+ (ftemp - state->frequency * 1000 >= fcp + state->srate / 4))
+ loop = 0;
+ }
+ }
+
+ loop = 1;
+ ftemp = fOSC_start * 1000;
+ vmin = 0 ;
+ while (loop == 1) {
+ ftemp = ftemp - swp_ofs;
+ vmin--;
+
+ /* Lower bound */
+ if (ftemp < 950000) {
+ loop = 0;
+ vmin++;
+ } else {
+ if ((ftemp == 950000) ||
+ (state->frequency * 1000 - ftemp >= fcp + state->srate / 4))
+ loop = 0;
+ }
+ }
+
+ wait_t = (8000 + state->srate / 2) / state->srate;
+ if (wait_t == 0)
+ wait_t = 1;
+
+ i = 0;
+ j = 0;
+ prev_freq_num = 0;
+ loop = 1;
+ signal = 0;
+ vmax_his = 0;
+ vmin_his = 0;
+ v = 0;
+
+ while (loop == 1) {
+ swp_info_get(state, fOSC_start, state->srate,
+ v, R, swp_ofs, &fOSC,
+ &afcex_freq, &AFCEX_L, &AFCEX_H);
+
+ udelay(100);
+ if (rf_val_set(state, fOSC, state->srate, R) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+ return -1;
+ }
+ udelay(100);
+ if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
+ return -1;
+ }
+ if (srst(state) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "srst error");
+ return -1;
+ }
+ msleep_interruptible(wait_t);
+
+ if (mb86a16_read(state, 0x37, &SIG1) != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -1;
+ }
+ V[30 + v] = SIG1 ;
+ swp_freq = swp_freq_calcuation(state, i, v, V, vmax, vmin,
+ SIG1MIN, fOSC, afcex_freq,
+ swp_ofs, &SIG1); /* changed */
+
+ signal_dupl = 0;
+ for (j = 0; j < prev_freq_num; j++) {
+ if ((ABS(prev_swp_freq[j] - swp_freq)) < (swp_ofs * 3 / 2)) {
+ signal_dupl = 1;
+ dprintk(verbose, MB86A16_INFO, 1, "Probably Duplicate Signal, j = %d", j);
+ }
+ }
+ if ((signal_dupl == 0) && (swp_freq > 0) && (ABS(swp_freq - state->frequency * 1000) < fcp + state->srate / 6)) {
+ dprintk(verbose, MB86A16_DEBUG, 1, "------ Signal detect ------ [swp_freq=[%07d, srate=%05d]]", swp_freq, state->srate);
+ prev_swp_freq[prev_freq_num] = swp_freq;
+ prev_freq_num++;
+ swp_info_get2(state, state->srate, R, swp_freq,
+ &afcex_freq, &fOSC,
+ &AFCEX_L, &AFCEX_H);
+
+ if (rf_val_set(state, fOSC, state->srate, R) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+ return -1;
+ }
+ if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
+ return -1;
+ }
+ signal = signal_det(state, state->srate, &SIG1);
+ if (signal == 1) {
+ dprintk(verbose, MB86A16_ERROR, 1, "***** Signal Found *****");
+ loop = 0;
+ } else {
+ dprintk(verbose, MB86A16_ERROR, 1, "!!!!! No signal !!!!!, try again...");
+ smrt_info_get(state, state->srate);
+ if (smrt_set(state, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
+ return -1;
+ }
+ }
+ }
+ if (v > vmax)
+ vmax_his = 1 ;
+ if (v < vmin)
+ vmin_his = 1 ;
+ i++;
+
+ if ((i % 2 == 1) && (vmax_his == 1))
+ i++;
+ if ((i % 2 == 0) && (vmin_his == 1))
+ i++;
+
+ if (i % 2 == 1)
+ v = (i + 1) / 2;
+ else
+ v = -i / 2;
+
+ if ((vmax_his == 1) && (vmin_his == 1))
+ loop = 0 ;
+ }
+
+ if (signal == 1) {
+ dprintk(verbose, MB86A16_INFO, 1, " Start Freq Error Check");
+ S1T = 7 ;
+ S0T = 1 ;
+ CREN = 0 ;
+ AFCEN = 1 ;
+ AFCEXEN = 0 ;
+
+ if (S01T_set(state, S1T, S0T) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "S01T set error");
+ return -1;
+ }
+ smrt_info_get(state, state->srate);
+ if (smrt_set(state, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
+ return -1;
+ }
+ if (EN_set(state, CREN, AFCEN) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "EN set error");
+ return -1;
+ }
+ if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
+ return -1;
+ }
+ afcex_info_get(state, afcex_freq, &AFCEX_L, &AFCEX_H);
+ if (afcofs_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "AFCOFS data set error");
+ return -1;
+ }
+ if (srst(state) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "srst error");
+ return -1;
+ }
+ /* delay 4~200 */
+ wait_t = 200000 / state->master_clk + 200000 / state->srate;
+ msleep(wait_t);
+ afcerr = afcerr_chk(state);
+ if (afcerr == -1)
+ return -1;
+
+ swp_freq = fOSC * 1000 + afcerr ;
+ AFCEXEN = 1 ;
+ if (state->srate >= 1500)
+ smrt_d = state->srate / 3;
+ else
+ smrt_d = state->srate / 2;
+ smrt_info_get(state, smrt_d);
+ if (smrt_set(state, smrt_d) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
+ return -1;
+ }
+ if (AFCEXEN_set(state, AFCEXEN, smrt_d) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
+ return -1;
+ }
+ R = vco_dev_get(state, smrt_d);
+ if (DAGC_data_set(state, 2, 0) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error");
+ return -1;
+ }
+ for (i = 0; i < 3; i++) {
+ temp_freq = swp_freq + (i - 1) * state->srate / 8;
+ swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
+ if (rf_val_set(state, fOSC, smrt_d, R) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+ return -1;
+ }
+ if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
+ return -1;
+ }
+ wait_t = 200000 / state->master_clk + 40000 / smrt_d;
+ msleep(wait_t);
+ dagcm[i] = dagcm_val_get(state);
+ }
+ if ((dagcm[0] > dagcm[1]) &&
+ (dagcm[0] > dagcm[2]) &&
+ (dagcm[0] - dagcm[1] > 2 * (dagcm[2] - dagcm[1]))) {
+
+ temp_freq = swp_freq - 2 * state->srate / 8;
+ swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
+ if (rf_val_set(state, fOSC, smrt_d, R) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+ return -1;
+ }
+ if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "afcex data set");
+ return -1;
+ }
+ wait_t = 200000 / state->master_clk + 40000 / smrt_d;
+ msleep(wait_t);
+ dagcm[3] = dagcm_val_get(state);
+ if (dagcm[3] > dagcm[1])
+ delta_freq = (dagcm[2] - dagcm[0] + dagcm[1] - dagcm[3]) * state->srate / 300;
+ else
+ delta_freq = 0;
+ } else if ((dagcm[2] > dagcm[1]) &&
+ (dagcm[2] > dagcm[0]) &&
+ (dagcm[2] - dagcm[1] > 2 * (dagcm[0] - dagcm[1]))) {
+
+ temp_freq = swp_freq + 2 * state->srate / 8;
+ swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
+ if (rf_val_set(state, fOSC, smrt_d, R) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "rf val set");
+ return -1;
+ }
+ if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "afcex data set");
+ return -1;
+ }
+ wait_t = 200000 / state->master_clk + 40000 / smrt_d;
+ msleep(wait_t);
+ dagcm[3] = dagcm_val_get(state);
+ if (dagcm[3] > dagcm[1])
+ delta_freq = (dagcm[2] - dagcm[0] + dagcm[3] - dagcm[1]) * state->srate / 300;
+ else
+ delta_freq = 0 ;
+
+ } else {
+ delta_freq = 0 ;
+ }
+ dprintk(verbose, MB86A16_INFO, 1, "SWEEP Frequency = %d", swp_freq);
+ swp_freq += delta_freq;
+ dprintk(verbose, MB86A16_INFO, 1, "Adjusting .., DELTA Freq = %d, SWEEP Freq=%d", delta_freq, swp_freq);
+ if (ABS(state->frequency * 1000 - swp_freq) > 3800) {
+ dprintk(verbose, MB86A16_INFO, 1, "NO -- SIGNAL !");
+ } else {
+
+ S1T = 0;
+ S0T = 3;
+ CREN = 1;
+ AFCEN = 0;
+ AFCEXEN = 1;
+
+ if (S01T_set(state, S1T, S0T) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "S01T set error");
+ return -1;
+ }
+ if (DAGC_data_set(state, 0, 0) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error");
+ return -1;
+ }
+ R = vco_dev_get(state, state->srate);
+ smrt_info_get(state, state->srate);
+ if (smrt_set(state, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
+ return -1;
+ }
+ if (EN_set(state, CREN, AFCEN) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "EN set error");
+ return -1;
+ }
+ if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
+ return -1;
+ }
+ swp_info_get2(state, state->srate, R, swp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
+ if (rf_val_set(state, fOSC, state->srate, R) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+ return -1;
+ }
+ if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
+ return -1;
+ }
+ if (srst(state) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "srst error");
+ return -1;
+ }
+ wait_t = 7 + (10000 + state->srate / 2) / state->srate;
+ if (wait_t == 0)
+ wait_t = 1;
+ msleep_interruptible(wait_t);
+ if (mb86a16_read(state, 0x37, &SIG1) != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ if (SIG1 > 110) {
+ S2T = 4; S4T = 1; S5T = 6; ETH = 4; VIA = 6;
+ wait_t = 7 + (917504 + state->srate / 2) / state->srate;
+ } else if (SIG1 > 105) {
+ S2T = 4; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
+ wait_t = 7 + (1048576 + state->srate / 2) / state->srate;
+ } else if (SIG1 > 85) {
+ S2T = 5; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
+ wait_t = 7 + (1310720 + state->srate / 2) / state->srate;
+ } else if (SIG1 > 65) {
+ S2T = 6; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
+ wait_t = 7 + (1572864 + state->srate / 2) / state->srate;
+ } else {
+ S2T = 7; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
+ wait_t = 7 + (2097152 + state->srate / 2) / state->srate;
+ }
+ wait_t *= 2; /* FOS */
+ S2T_set(state, S2T);
+ S45T_set(state, S4T, S5T);
+ Vi_set(state, ETH, VIA);
+ srst(state);
+ msleep_interruptible(wait_t);
+ sync = sync_chk(state, &VIRM);
+ dprintk(verbose, MB86A16_INFO, 1, "-------- Viterbi=[%d] SYNC=[%d] ---------", VIRM, sync);
+ if (VIRM) {
+ if (VIRM == 4) {
+ /* 5/6 */
+ if (SIG1 > 110)
+ wait_t = (786432 + state->srate / 2) / state->srate;
+ else
+ wait_t = (1572864 + state->srate / 2) / state->srate;
+ if (state->srate < 5000)
+ /* FIXME ! , should be a long wait ! */
+ msleep_interruptible(wait_t);
+ else
+ msleep_interruptible(wait_t);
+
+ if (sync_chk(state, &junk) == 0) {
+ iq_vt_set(state, 1);
+ FEC_srst(state);
+ }
+ }
+ /* 1/2, 2/3, 3/4, 7/8 */
+ if (SIG1 > 110)
+ wait_t = (786432 + state->srate / 2) / state->srate;
+ else
+ wait_t = (1572864 + state->srate / 2) / state->srate;
+ msleep_interruptible(wait_t);
+ SEQ_set(state, 1);
+ } else {
+ dprintk(verbose, MB86A16_INFO, 1, "NO -- SYNC");
+ SEQ_set(state, 1);
+ ret = -1;
+ }
+ }
+ } else {
+ dprintk(verbose, MB86A16_INFO, 1, "NO -- SIGNAL");
+ ret = -1;
+ }
+
+ sync = sync_chk(state, &junk);
+ if (sync) {
+ dprintk(verbose, MB86A16_INFO, 1, "******* SYNC *******");
+ freqerr_chk(state, state->frequency, state->srate, 1);
+ ret = 0;
+ break;
+ }
+ }
+
+ mb86a16_read(state, 0x15, &agcval);
+ mb86a16_read(state, 0x26, &cnmval);
+ dprintk(verbose, MB86A16_INFO, 1, "AGC = %02x CNM = %02x", agcval, cnmval);
+
+ return ret;
+}
+
+static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe,
+ struct dvb_diseqc_master_cmd *cmd)
+{
+ struct mb86a16_state *state = fe->demodulator_priv;
+ int i;
+ u8 regs;
+
+ if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCCOUT, 0x00) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_TONEOUT2, 0x04) < 0)
+ goto err;
+
+ regs = 0x18;
+
+ if (cmd->msg_len > 5 || cmd->msg_len < 4)
+ return -EINVAL;
+
+ for (i = 0; i < cmd->msg_len; i++) {
+ if (mb86a16_write(state, regs, cmd->msg[i]) < 0)
+ goto err;
+
+ regs++;
+ }
+ i += 0x90;
+
+ msleep_interruptible(10);
+
+ if (mb86a16_write(state, MB86A16_DCC1, i) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int mb86a16_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst)
+{
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ switch (burst) {
+ case SEC_MINI_A:
+ if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA |
+ MB86A16_DCC1_TBEN |
+ MB86A16_DCC1_TBO) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
+ goto err;
+ break;
+ case SEC_MINI_B:
+ if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA |
+ MB86A16_DCC1_TBEN) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
+ goto err;
+ break;
+ }
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int mb86a16_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ switch (tone) {
+ case SEC_TONE_ON:
+ if (mb86a16_write(state, MB86A16_TONEOUT2, 0x00) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA |
+ MB86A16_DCC1_CTOE) < 0)
+
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
+ goto err;
+ break;
+ case SEC_TONE_OFF:
+ if (mb86a16_write(state, MB86A16_TONEOUT2, 0x04) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCCOUT, 0x00) < 0)
+ goto err;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static enum dvbfe_search mb86a16_search(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ state->frequency = p->frequency / 1000;
+ state->srate = p->u.qpsk.symbol_rate / 1000;
+
+ if (!mb86a16_set_fe(state)) {
+ dprintk(verbose, MB86A16_ERROR, 1, "Succesfully acquired LOCK");
+ return DVBFE_ALGO_SEARCH_SUCCESS;
+ }
+
+ dprintk(verbose, MB86A16_ERROR, 1, "Lock acquisition failed!");
+ return DVBFE_ALGO_SEARCH_FAILED;
+}
+
+static void mb86a16_release(struct dvb_frontend *fe)
+{
+ struct mb86a16_state *state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static int mb86a16_init(struct dvb_frontend *fe)
+{
+ return 0;
+}
+
+static int mb86a16_sleep(struct dvb_frontend *fe)
+{
+ return 0;
+}
+
+static int mb86a16_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ u8 ber_mon, ber_tab, ber_lsb, ber_mid, ber_msb, ber_tim, ber_rst;
+ u32 timer;
+
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ *ber = 0;
+ if (mb86a16_read(state, MB86A16_BERMON, &ber_mon) != 2)
+ goto err;
+ if (mb86a16_read(state, MB86A16_BERTAB, &ber_tab) != 2)
+ goto err;
+ if (mb86a16_read(state, MB86A16_BERLSB, &ber_lsb) != 2)
+ goto err;
+ if (mb86a16_read(state, MB86A16_BERMID, &ber_mid) != 2)
+ goto err;
+ if (mb86a16_read(state, MB86A16_BERMSB, &ber_msb) != 2)
+ goto err;
+ /* BER monitor invalid when BER_EN = 0 */
+ if (ber_mon & 0x04) {
+ /* coarse, fast calculation */
+ *ber = ber_tab & 0x1f;
+ dprintk(verbose, MB86A16_DEBUG, 1, "BER coarse=[0x%02x]", *ber);
+ if (ber_mon & 0x01) {
+ /*
+ * BER_SEL = 1, The monitored BER is the estimated
+ * value with a Reed-Solomon decoder error amount at
+ * the deinterleaver output.
+ * monitored BER is expressed as a 20 bit output in total
+ */
+ ber_rst = ber_mon >> 3;
+ *ber = (((ber_msb << 8) | ber_mid) << 8) | ber_lsb;
+ if (ber_rst == 0)
+ timer = 12500000;
+ if (ber_rst == 1)
+ timer = 25000000;
+ if (ber_rst == 2)
+ timer = 50000000;
+ if (ber_rst == 3)
+ timer = 100000000;
+
+ *ber /= timer;
+ dprintk(verbose, MB86A16_DEBUG, 1, "BER fine=[0x%02x]", *ber);
+ } else {
+ /*
+ * BER_SEL = 0, The monitored BER is the estimated
+ * value with a Viterbi decoder error amount at the
+ * QPSK demodulator output.
+ * monitored BER is expressed as a 24 bit output in total
+ */
+ ber_tim = ber_mon >> 1;
+ *ber = (((ber_msb << 8) | ber_mid) << 8) | ber_lsb;
+ if (ber_tim == 0)
+ timer = 16;
+ if (ber_tim == 1)
+ timer = 24;
+
+ *ber /= 2 ^ timer;
+ dprintk(verbose, MB86A16_DEBUG, 1, "BER fine=[0x%02x]", *ber);
+ }
+ }
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int mb86a16_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ u8 agcm = 0;
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ *strength = 0;
+ if (mb86a16_read(state, MB86A16_AGCM, &agcm) != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ *strength = ((0xff - agcm) * 100) / 256;
+ dprintk(verbose, MB86A16_DEBUG, 1, "Signal strength=[%d %%]", (u8) *strength);
+ *strength = (0xffff - 0xff) + agcm;
+
+ return 0;
+}
+
+struct cnr {
+ u8 cn_reg;
+ u8 cn_val;
+};
+
+static const struct cnr cnr_tab[] = {
+ { 35, 2 },
+ { 40, 3 },
+ { 50, 4 },
+ { 60, 5 },
+ { 70, 6 },
+ { 80, 7 },
+ { 92, 8 },
+ { 103, 9 },
+ { 115, 10 },
+ { 138, 12 },
+ { 162, 15 },
+ { 180, 18 },
+ { 185, 19 },
+ { 189, 20 },
+ { 195, 22 },
+ { 199, 24 },
+ { 201, 25 },
+ { 202, 26 },
+ { 203, 27 },
+ { 205, 28 },
+ { 208, 30 }
+};
+
+static int mb86a16_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct mb86a16_state *state = fe->demodulator_priv;
+ int i = 0;
+ int low_tide = 2, high_tide = 30, q_level;
+ u8 cn;
+
+ *snr = 0;
+ if (mb86a16_read(state, 0x26, &cn) != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cnr_tab); i++) {
+ if (cn < cnr_tab[i].cn_reg) {
+ *snr = cnr_tab[i].cn_val;
+ break;
+ }
+ }
+ q_level = (*snr * 100) / (high_tide - low_tide);
+ dprintk(verbose, MB86A16_ERROR, 1, "SNR (Quality) = [%d dB], Level=%d %%", *snr, q_level);
+ *snr = (0xffff - 0xff) + *snr;
+
+ return 0;
+}
+
+static int mb86a16_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ u8 dist;
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ if (mb86a16_read(state, MB86A16_DISTMON, &dist) != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+ *ucblocks = dist;
+
+ return 0;
+}
+
+static enum dvbfe_algo mb86a16_frontend_algo(struct dvb_frontend *fe)
+{
+ return DVBFE_ALGO_CUSTOM;
+}
+
+static struct dvb_frontend_ops mb86a16_ops = {
+ .info = {
+ .name = "Fujitsu MB86A16 DVB-S",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 3000,
+ .frequency_tolerance = 0,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ .symbol_rate_tolerance = 500,
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
+ FE_CAN_FEC_7_8 | FE_CAN_QPSK |
+ FE_CAN_FEC_AUTO
+ },
+ .release = mb86a16_release,
+
+ .get_frontend_algo = mb86a16_frontend_algo,
+ .search = mb86a16_search,
+ .read_status = mb86a16_read_status,
+ .init = mb86a16_init,
+ .sleep = mb86a16_sleep,
+ .read_status = mb86a16_read_status,
+
+ .read_ber = mb86a16_read_ber,
+ .read_signal_strength = mb86a16_read_signal_strength,
+ .read_snr = mb86a16_read_snr,
+ .read_ucblocks = mb86a16_read_ucblocks,
+
+ .diseqc_send_master_cmd = mb86a16_send_diseqc_msg,
+ .diseqc_send_burst = mb86a16_send_diseqc_burst,
+ .set_tone = mb86a16_set_tone,
+};
+
+struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
+ struct i2c_adapter *i2c_adap)
+{
+ u8 dev_id = 0;
+ struct mb86a16_state *state = NULL;
+
+ state = kmalloc(sizeof(struct mb86a16_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ state->config = config;
+ state->i2c_adap = i2c_adap;
+
+ mb86a16_read(state, 0x7f, &dev_id);
+ if (dev_id != 0xfe)
+ goto error;
+
+ memcpy(&state->frontend.ops, &mb86a16_ops, sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+ state->frontend.ops.set_voltage = state->config->set_voltage;
+
+ return &state->frontend;
+error:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(mb86a16_attach);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Manu Abraham");
diff --git a/drivers/media/dvb/frontends/mb86a16.h b/drivers/media/dvb/frontends/mb86a16.h
new file mode 100644
index 00000000000..6ea8c376394
--- /dev/null
+++ b/drivers/media/dvb/frontends/mb86a16.h
@@ -0,0 +1,52 @@
+/*
+ Fujitsu MB86A16 DVB-S/DSS DC Receiver driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MB86A16_H
+#define __MB86A16_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+
+struct mb86a16_config {
+ u8 demod_address;
+
+ int (*set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+};
+
+
+
+#if defined(CONFIG_DVB_MB86A16) || (defined(CONFIG_DVB_MB86A16_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
+ struct i2c_adapter *i2c_adap);
+
+#else
+
+static inline struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
+ struct i2c_adapter *i2c_adap)
+{
+ printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+
+#endif /* CONFIG_DVB_MB86A16 */
+
+#endif /* __MB86A16_H */
diff --git a/drivers/media/dvb/frontends/mb86a16_priv.h b/drivers/media/dvb/frontends/mb86a16_priv.h
new file mode 100644
index 00000000000..360a35acfe8
--- /dev/null
+++ b/drivers/media/dvb/frontends/mb86a16_priv.h
@@ -0,0 +1,151 @@
+/*
+ Fujitsu MB86A16 DVB-S/DSS DC Receiver driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MB86A16_PRIV_H
+#define __MB86A16_PRIV_H
+
+#define MB86A16_TSOUT 0x00
+#define MB86A16_TSOUT_HIZSEL (0x01 << 5)
+#define MB86A16_TSOUT_HIZCNTI (0x01 << 4)
+#define MB86A16_TSOUT_MODE (0x01 << 3)
+#define MB86A16_TSOUT_ORDER (0x01 << 2)
+#define MB86A16_TSOUT_ERROR (0x01 << 1)
+#define Mb86A16_TSOUT_EDGE (0x01 << 0)
+
+#define MB86A16_FEC 0x01
+#define MB86A16_FEC_FSYNC (0x01 << 5)
+#define MB86A16_FEC_PCKB8 (0x01 << 4)
+#define MB86A16_FEC_DVDS (0x01 << 3)
+#define MB86A16_FEC_EREN (0x01 << 2)
+#define Mb86A16_FEC_RSEN (0x01 << 1)
+#define MB86A16_FEC_DIEN (0x01 << 0)
+
+#define MB86A16_AGC 0x02
+#define MB86A16_AGC_AGMD (0x01 << 6)
+#define MB86A16_AGC_AGCW (0x0f << 2)
+#define MB86A16_AGC_AGCP (0x01 << 1)
+#define MB86A16_AGC_AGCR (0x01 << 0)
+
+#define MB86A16_SRATE1 0x03
+#define MB86A16_SRATE1_DECI (0x07 << 2)
+#define MB86A16_SRATE1_CSEL (0x01 << 1)
+#define MB86A16_SRATE1_RSEL (0x01 << 0)
+
+#define MB86A16_SRATE2 0x04
+#define MB86A16_SRATE2_STOFSL (0xff << 0)
+
+#define MB86A16_SRATE3 0x05
+#define MB86A16_SRATE2_STOFSH (0xff << 0)
+
+#define MB86A16_VITERBI 0x06
+#define MB86A16_FRAMESYNC 0x07
+#define MB86A16_CRLFILTCOEF1 0x08
+#define MB86A16_CRLFILTCOEF2 0x09
+#define MB86A16_STRFILTCOEF1 0x0a
+#define MB86A16_STRFILTCOEF2 0x0b
+#define MB86A16_RESET 0x0c
+#define MB86A16_STATUS 0x0d
+#define MB86A16_AFCML 0x0e
+#define MB86A16_AFCMH 0x0f
+#define MB86A16_BERMON 0x10
+#define MB86A16_BERTAB 0x11
+#define MB86A16_BERLSB 0x12
+#define MB86A16_BERMID 0x13
+#define MB86A16_BERMSB 0x14
+#define MB86A16_AGCM 0x15
+
+#define MB86A16_DCC1 0x16
+#define MB86A16_DCC1_DISTA (0x01 << 7)
+#define MB86A16_DCC1_PRTY (0x01 << 6)
+#define MB86A16_DCC1_CTOE (0x01 << 5)
+#define MB86A16_DCC1_TBEN (0x01 << 4)
+#define MB86A16_DCC1_TBO (0x01 << 3)
+#define MB86A16_DCC1_NUM (0x07 << 0)
+
+#define MB86A16_DCC2 0x17
+#define MB86A16_DCC2_DCBST (0x01 << 0)
+
+#define MB86A16_DCC3 0x18
+#define MB86A16_DCC3_CODE0 (0xff << 0)
+
+#define MB86A16_DCC4 0x19
+#define MB86A16_DCC4_CODE1 (0xff << 0)
+
+#define MB86A16_DCC5 0x1a
+#define MB86A16_DCC5_CODE2 (0xff << 0)
+
+#define MB86A16_DCC6 0x1b
+#define MB86A16_DCC6_CODE3 (0xff << 0)
+
+#define MB86A16_DCC7 0x1c
+#define MB86A16_DCC7_CODE4 (0xff << 0)
+
+#define MB86A16_DCC8 0x1d
+#define MB86A16_DCC8_CODE5 (0xff << 0)
+
+#define MB86A16_DCCOUT 0x1e
+#define MB86A16_DCCOUT_DISEN (0x01 << 0)
+
+#define MB86A16_TONEOUT1 0x1f
+#define MB86A16_TONE_TDIVL (0xff << 0)
+
+#define MB86A16_TONEOUT2 0x20
+#define MB86A16_TONE_TMD (0x03 << 2)
+#define MB86A16_TONE_TDIVH (0x03 << 0)
+
+#define MB86A16_FREQ1 0x21
+#define MB86A16_FREQ2 0x22
+#define MB86A16_FREQ3 0x23
+#define MB86A16_FREQ4 0x24
+#define MB86A16_FREQSET 0x25
+#define MB86A16_CNM 0x26
+#define MB86A16_PORT0 0x27
+#define MB86A16_PORT1 0x28
+#define MB86A16_DRCFILT 0x29
+#define MB86A16_AFC 0x2a
+#define MB86A16_AFCEXL 0x2b
+#define MB86A16_AFCEXH 0x2c
+#define MB86A16_DAGC 0x2d
+#define MB86A16_SEQMODE 0x32
+#define MB86A16_S0S1T 0x33
+#define MB86A16_S2S3T 0x34
+#define MB86A16_S4S5T 0x35
+#define MB86A16_CNTMR 0x36
+#define MB86A16_SIG1 0x37
+#define MB86A16_SIG2 0x38
+#define MB86A16_VIMAG 0x39
+#define MB86A16_VISET1 0x3a
+#define MB86A16_VISET2 0x3b
+#define MB86A16_VISET3 0x3c
+#define MB86A16_FAGCS1 0x3d
+#define MB86A16_FAGCS2 0x3e
+#define MB86A16_FAGCS3 0x3f
+#define MB86A16_FAGCS4 0x40
+#define MB86A16_FAGCS5 0x41
+#define MB86A16_FAGCS6 0x42
+#define MB86A16_CRM 0x43
+#define MB86A16_STRM 0x44
+#define MB86A16_DAGCML 0x45
+#define MB86A16_DAGCMH 0x46
+#define MB86A16_QPSKTST 0x49
+#define MB86A16_DISTMON 0x52
+#define MB86A16_VERSION 0x7f
+
+#endif /* __MB86A16_PRIV_H */
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index 6c1dbf9288d..6ca533ea0f0 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -426,6 +426,10 @@ struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
id = tda10021_readreg(state, 0x1a);
if ((id & 0xf0) != 0x70) goto error;
+ /* Don't claim TDA10023 */
+ if (id == 0x7d)
+ goto error;
+
printk("TDA10021: i2c-addr = 0x%02x, id = 0x%02x\n",
state->config->demod_address, id);
diff --git a/drivers/media/dvb/frontends/tda665x.c b/drivers/media/dvb/frontends/tda665x.c
new file mode 100644
index 00000000000..87d52739c82
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda665x.c
@@ -0,0 +1,257 @@
+/*
+ TDA665x tuner driver
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "dvb_frontend.h"
+#include "tda665x.h"
+
+struct tda665x_state {
+ struct dvb_frontend *fe;
+ struct i2c_adapter *i2c;
+ const struct tda665x_config *config;
+
+ u32 frequency;
+ u32 bandwidth;
+};
+
+static int tda665x_read(struct tda665x_state *state, u8 *buf)
+{
+ const struct tda665x_config *config = state->config;
+ int err = 0;
+ struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD, .buf = buf, .len = 2 };
+
+ err = i2c_transfer(state->i2c, &msg, 1);
+ if (err != 1)
+ goto exit;
+
+ return err;
+exit:
+ printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err);
+ return err;
+}
+
+static int tda665x_write(struct tda665x_state *state, u8 *buf, u8 length)
+{
+ const struct tda665x_config *config = state->config;
+ int err = 0;
+ struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = length };
+
+ err = i2c_transfer(state->i2c, &msg, 1);
+ if (err != 1)
+ goto exit;
+
+ return err;
+exit:
+ printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err);
+ return err;
+}
+
+static int tda665x_get_state(struct dvb_frontend *fe,
+ enum tuner_param param,
+ struct tuner_state *tstate)
+{
+ struct tda665x_state *state = fe->tuner_priv;
+ int err = 0;
+
+ switch (param) {
+ case DVBFE_TUNER_FREQUENCY:
+ tstate->frequency = state->frequency;
+ break;
+ case DVBFE_TUNER_BANDWIDTH:
+ break;
+ default:
+ printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param);
+ err = -EINVAL;
+ break;
+ }
+
+ return err;
+}
+
+static int tda665x_get_status(struct dvb_frontend *fe, u32 *status)
+{
+ struct tda665x_state *state = fe->tuner_priv;
+ u8 result = 0;
+ int err = 0;
+
+ *status = 0;
+
+ err = tda665x_read(state, &result);
+ if (err < 0)
+ goto exit;
+
+ if ((result >> 6) & 0x01) {
+ printk(KERN_DEBUG "%s: Tuner Phase Locked\n", __func__);
+ *status = 1;
+ }
+
+ return err;
+exit:
+ printk(KERN_ERR "%s: I/O Error\n", __func__);
+ return err;
+}
+
+static int tda665x_set_state(struct dvb_frontend *fe,
+ enum tuner_param param,
+ struct tuner_state *tstate)
+{
+ struct tda665x_state *state = fe->tuner_priv;
+ const struct tda665x_config *config = state->config;
+ u32 frequency, status = 0;
+ u8 buf[4];
+ int err = 0;
+
+ if (param & DVBFE_TUNER_FREQUENCY) {
+
+ frequency = tstate->frequency;
+ if ((frequency < config->frequency_max) || (frequency > config->frequency_min)) {
+ printk(KERN_ERR "%s: Frequency beyond limits, frequency=%d\n", __func__, frequency);
+ return -EINVAL;
+ }
+
+ frequency += config->frequency_offst;
+ frequency *= config->ref_multiplier;
+ frequency += config->ref_divider >> 1;
+ frequency /= config->ref_divider;
+
+ buf[0] = (u8) (frequency & 0x7f00) >> 8;
+ buf[1] = (u8) (frequency & 0x00ff) >> 0;
+ buf[2] = 0x80 | 0x40 | 0x02;
+ buf[3] = 0x00;
+
+ /* restore frequency */
+ frequency = tstate->frequency;
+
+ if (frequency < 153000000) {
+ /* VHF-L */
+ buf[3] |= 0x01; /* fc, Low Band, 47 - 153 MHz */
+ if (frequency < 68000000)
+ buf[3] |= 0x40; /* 83uA */
+ if (frequency < 1040000000)
+ buf[3] |= 0x60; /* 122uA */
+ if (frequency < 1250000000)
+ buf[3] |= 0x80; /* 163uA */
+ else
+ buf[3] |= 0xa0; /* 254uA */
+ } else if (frequency < 438000000) {
+ /* VHF-H */
+ buf[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */
+ if (frequency < 230000000)
+ buf[3] |= 0x40;
+ if (frequency < 300000000)
+ buf[3] |= 0x60;
+ else
+ buf[3] |= 0x80;
+ } else {
+ /* UHF */
+ buf[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */
+ if (frequency < 470000000)
+ buf[3] |= 0x60;
+ if (frequency < 526000000)
+ buf[3] |= 0x80;
+ else
+ buf[3] |= 0xa0;
+ }
+
+ /* Set params */
+ err = tda665x_write(state, buf, 5);
+ if (err < 0)
+ goto exit;
+
+ /* sleep for some time */
+ printk(KERN_DEBUG "%s: Waiting to Phase LOCK\n", __func__);
+ msleep(20);
+ /* check status */
+ err = tda665x_get_status(fe, &status);
+ if (err < 0)
+ goto exit;
+
+ if (status == 1) {
+ printk(KERN_DEBUG "%s: Tuner Phase locked: status=%d\n", __func__, status);
+ state->frequency = frequency; /* cache successful state */
+ } else {
+ printk(KERN_ERR "%s: No Phase lock: status=%d\n", __func__, status);
+ }
+ } else {
+ printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param);
+ return -EINVAL;
+ }
+
+ return 0;
+exit:
+ printk(KERN_ERR "%s: I/O Error\n", __func__);
+ return err;
+}
+
+static int tda665x_release(struct dvb_frontend *fe)
+{
+ struct tda665x_state *state = fe->tuner_priv;
+
+ fe->tuner_priv = NULL;
+ kfree(state);
+ return 0;
+}
+
+static struct dvb_tuner_ops tda665x_ops = {
+
+ .set_state = tda665x_set_state,
+ .get_state = tda665x_get_state,
+ .get_status = tda665x_get_status,
+ .release = tda665x_release
+};
+
+struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
+ const struct tda665x_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct tda665x_state *state = NULL;
+ struct dvb_tuner_info *info;
+
+ state = kzalloc(sizeof(struct tda665x_state), GFP_KERNEL);
+ if (state == NULL)
+ goto exit;
+
+ state->config = config;
+ state->i2c = i2c;
+ state->fe = fe;
+ fe->tuner_priv = state;
+ fe->ops.tuner_ops = tda665x_ops;
+ info = &fe->ops.tuner_ops.info;
+
+ memcpy(info->name, config->name, sizeof(config->name));
+ info->frequency_min = config->frequency_min;
+ info->frequency_max = config->frequency_max;
+ info->frequency_step = config->frequency_offst;
+
+ printk(KERN_DEBUG "%s: Attaching TDA665x (%s) tuner\n", __func__, info->name);
+
+ return fe;
+
+exit:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(tda665x_attach);
+
+MODULE_DESCRIPTION("TDA665x driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tda665x.h b/drivers/media/dvb/frontends/tda665x.h
new file mode 100644
index 00000000000..ec7927aa75a
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda665x.h
@@ -0,0 +1,52 @@
+/*
+ TDA665x tuner driver
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __TDA665x_H
+#define __TDA665x_H
+
+struct tda665x_config {
+ char name[128];
+
+ u8 addr;
+ u32 frequency_min;
+ u32 frequency_max;
+ u32 frequency_offst;
+ u32 ref_multiplier;
+ u32 ref_divider;
+};
+
+#if defined(CONFIG_DVB_TDA665x) || (defined(CONFIG_DVB_TDA665x_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
+ const struct tda665x_config *config,
+ struct i2c_adapter *i2c);
+
+#else
+
+static inline struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
+ const struct tda665x_config *config,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+
+#endif /* CONFIG_DVB_TDA665x */
+
+#endif /* __TDA665x_H */
diff --git a/drivers/media/dvb/mantis/Kconfig b/drivers/media/dvb/mantis/Kconfig
new file mode 100644
index 00000000000..f7b72a32adf
--- /dev/null
+++ b/drivers/media/dvb/mantis/Kconfig
@@ -0,0 +1,32 @@
+config MANTIS_CORE
+ tristate "Mantis/Hopper PCI bridge based devices"
+ depends on PCI && I2C && INPUT
+
+ help
+ Support for PCI cards based on the Mantis and Hopper PCi bridge.
+
+ Say Y if you own such a device and want to use it.
+
+config DVB_MANTIS
+ tristate "MANTIS based cards"
+ depends on MANTIS_CORE && DVB_CORE && PCI && I2C
+ select DVB_MB86A16
+ select DVB_ZL10353
+ select DVB_STV0299
+ select DVB_PLL
+ help
+ Support for PCI cards based on the Mantis PCI bridge.
+ Say Y when you have a Mantis based DVB card and want to use it.
+
+ If unsure say N.
+
+config DVB_HOPPER
+ tristate "HOPPER based cards"
+ depends on MANTIS_CORE && DVB_CORE && PCI && I2C
+ select DVB_ZL10353
+ select DVB_PLL
+ help
+ Support for PCI cards based on the Hopper PCI bridge.
+ Say Y when you have a Hopper based DVB card and want to use it.
+
+ If unsure say N
diff --git a/drivers/media/dvb/mantis/Makefile b/drivers/media/dvb/mantis/Makefile
new file mode 100644
index 00000000000..98dc5cd258a
--- /dev/null
+++ b/drivers/media/dvb/mantis/Makefile
@@ -0,0 +1,28 @@
+mantis_core-objs := mantis_ioc.o \
+ mantis_uart.o \
+ mantis_dma.o \
+ mantis_pci.o \
+ mantis_i2c.o \
+ mantis_dvb.o \
+ mantis_evm.o \
+ mantis_hif.o \
+ mantis_ca.o \
+ mantis_pcmcia.o \
+ mantis_input.o
+
+mantis-objs := mantis_cards.o \
+ mantis_vp1033.o \
+ mantis_vp1034.o \
+ mantis_vp1041.o \
+ mantis_vp2033.o \
+ mantis_vp2040.o \
+ mantis_vp3030.o
+
+hopper-objs := hopper_cards.o \
+ hopper_vp3028.o
+
+obj-$(CONFIG_MANTIS_CORE) += mantis_core.o
+obj-$(CONFIG_DVB_MANTIS) += mantis.o
+obj-$(CONFIG_DVB_HOPPER) += hopper.o
+
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/mantis/hopper_cards.c b/drivers/media/dvb/mantis/hopper_cards.c
new file mode 100644
index 00000000000..d073c61e3c0
--- /dev/null
+++ b/drivers/media/dvb/mantis/hopper_cards.c
@@ -0,0 +1,275 @@
+/*
+ Hopper PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <asm/irq.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "hopper_vp3028.h"
+#include "mantis_dma.h"
+#include "mantis_dvb.h"
+#include "mantis_uart.h"
+#include "mantis_ioc.h"
+#include "mantis_pci.h"
+#include "mantis_i2c.h"
+#include "mantis_reg.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
+
+#define DRIVER_NAME "Hopper"
+
+static char *label[10] = {
+ "DMA",
+ "IRQ-0",
+ "IRQ-1",
+ "OCERR",
+ "PABRT",
+ "RIPRR",
+ "PPERR",
+ "FTRGT",
+ "RISCI",
+ "RACK"
+};
+
+static int devs;
+
+static irqreturn_t hopper_irq_handler(int irq, void *dev_id)
+{
+ u32 stat = 0, mask = 0, lstat = 0, mstat = 0;
+ u32 rst_stat = 0, rst_mask = 0;
+
+ struct mantis_pci *mantis;
+ struct mantis_ca *ca;
+
+ mantis = (struct mantis_pci *) dev_id;
+ if (unlikely(mantis == NULL)) {
+ dprintk(MANTIS_ERROR, 1, "Mantis == NULL");
+ return IRQ_NONE;
+ }
+ ca = mantis->mantis_ca;
+
+ stat = mmread(MANTIS_INT_STAT);
+ mask = mmread(MANTIS_INT_MASK);
+ mstat = lstat = stat & ~MANTIS_INT_RISCSTAT;
+ if (!(stat & mask))
+ return IRQ_NONE;
+
+ rst_mask = MANTIS_GPIF_WRACK |
+ MANTIS_GPIF_OTHERR |
+ MANTIS_SBUF_WSTO |
+ MANTIS_GPIF_EXTIRQ;
+
+ rst_stat = mmread(MANTIS_GPIF_STATUS);
+ rst_stat &= rst_mask;
+ mmwrite(rst_stat, MANTIS_GPIF_STATUS);
+
+ mantis->mantis_int_stat = stat;
+ mantis->mantis_int_mask = mask;
+ dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask);
+ if (stat & MANTIS_INT_RISCEN) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]);
+ }
+ if (stat & MANTIS_INT_IRQ0) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]);
+ mantis->gpif_status = rst_stat;
+ wake_up(&ca->hif_write_wq);
+ schedule_work(&ca->hif_evm_work);
+ }
+ if (stat & MANTIS_INT_IRQ1) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]);
+ schedule_work(&mantis->uart_work);
+ }
+ if (stat & MANTIS_INT_OCERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]);
+ }
+ if (stat & MANTIS_INT_PABORT) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]);
+ }
+ if (stat & MANTIS_INT_RIPERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]);
+ }
+ if (stat & MANTIS_INT_PPERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]);
+ }
+ if (stat & MANTIS_INT_FTRGT) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]);
+ }
+ if (stat & MANTIS_INT_RISCI) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
+ mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
+ tasklet_schedule(&mantis->tasklet);
+ }
+ if (stat & MANTIS_INT_I2CDONE) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);
+ wake_up(&mantis->i2c_wq);
+ }
+ mmwrite(stat, MANTIS_INT_STAT);
+ stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE |
+ MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 |
+ MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 |
+ MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 |
+ MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 |
+ MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 |
+ MANTIS_INT_IRQ0 | MANTIS_INT_OCERR |
+ MANTIS_INT_PABORT | MANTIS_INT_RIPERR |
+ MANTIS_INT_PPERR | MANTIS_INT_FTRGT |
+ MANTIS_INT_RISCI);
+
+ if (stat)
+ dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>", stat, mask);
+
+ dprintk(MANTIS_DEBUG, 0, "\n");
+ return IRQ_HANDLED;
+}
+
+static int __devinit hopper_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+{
+ struct mantis_pci *mantis;
+ struct mantis_hwconfig *config;
+ int err = 0;
+
+ mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL);
+ if (mantis == NULL) {
+ printk(KERN_ERR "%s ERROR: Out of memory\n", __func__);
+ err = -ENOMEM;
+ goto fail0;
+ }
+
+ mantis->num = devs;
+ mantis->verbose = verbose;
+ mantis->pdev = pdev;
+ config = (struct mantis_hwconfig *) pci_id->driver_data;
+ config->irq_handler = &hopper_irq_handler;
+ mantis->hwconfig = config;
+
+ err = mantis_pci_init(mantis);
+ if (err) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err);
+ goto fail1;
+ }
+
+ err = mantis_stream_control(mantis, STREAM_TO_HIF);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err);
+ goto fail1;
+ }
+
+ err = mantis_i2c_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err);
+ goto fail2;
+ }
+
+ err = mantis_get_mac(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err);
+ goto fail2;
+ }
+
+ err = mantis_dma_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err);
+ goto fail3;
+ }
+
+ err = mantis_dvb_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err);
+ goto fail4;
+ }
+ devs++;
+
+ return err;
+
+fail4:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err);
+ mantis_dma_exit(mantis);
+
+fail3:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err);
+ mantis_i2c_exit(mantis);
+
+fail2:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err);
+ mantis_pci_exit(mantis);
+
+fail1:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err);
+ kfree(mantis);
+
+fail0:
+ return err;
+}
+
+static void __devexit hopper_pci_remove(struct pci_dev *pdev)
+{
+ struct mantis_pci *mantis = pci_get_drvdata(pdev);
+
+ if (mantis) {
+ mantis_dvb_exit(mantis);
+ mantis_dma_exit(mantis);
+ mantis_i2c_exit(mantis);
+ mantis_pci_exit(mantis);
+ kfree(mantis);
+ }
+ return;
+
+}
+
+static struct pci_device_id hopper_pci_table[] = {
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config),
+ { }
+};
+
+static struct pci_driver hopper_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = hopper_pci_table,
+ .probe = hopper_pci_probe,
+ .remove = hopper_pci_remove,
+};
+
+static int __devinit hopper_init(void)
+{
+ return pci_register_driver(&hopper_pci_driver);
+}
+
+static void __devexit hopper_exit(void)
+{
+ return pci_unregister_driver(&hopper_pci_driver);
+}
+
+module_init(hopper_init);
+module_exit(hopper_exit);
+
+MODULE_DESCRIPTION("HOPPER driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/mantis/hopper_vp3028.c b/drivers/media/dvb/mantis/hopper_vp3028.c
new file mode 100644
index 00000000000..96674c78e86
--- /dev/null
+++ b/drivers/media/dvb/mantis/hopper_vp3028.c
@@ -0,0 +1,88 @@
+/*
+ Hopper VP-3028 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "zl10353.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "hopper_vp3028.h"
+
+struct zl10353_config hopper_vp3028_config = {
+ .demod_address = 0x0f,
+};
+
+#define MANTIS_MODEL_NAME "VP-3028"
+#define MANTIS_DEV_TYPE "DVB-T"
+
+static int vp3028_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ int err = 0;
+
+ gpio_set_bits(mantis, config->reset, 0);
+ msleep(100);
+ err = mantis_frontend_power(mantis, POWER_ON);
+ msleep(100);
+ gpio_set_bits(mantis, config->reset, 1);
+
+ err = mantis_frontend_power(mantis, POWER_ON);
+ if (err == 0) {
+ msleep(250);
+ dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)");
+ fe = zl10353_attach(&hopper_vp3028_config, adapter);
+
+ if (!fe)
+ return -1;
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+ }
+ dprintk(MANTIS_ERROR, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp3028_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_188,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp3028_frontend_init,
+ .power = GPIF_A00,
+ .reset = GPIF_A03,
+};
diff --git a/drivers/media/dvb/mantis/hopper_vp3028.h b/drivers/media/dvb/mantis/hopper_vp3028.h
new file mode 100644
index 00000000000..57239498bc8
--- /dev/null
+++ b/drivers/media/dvb/mantis/hopper_vp3028.h
@@ -0,0 +1,30 @@
+/*
+ Hopper VP-3028 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MANTIS_VP3028_H
+#define __MANTIS_VP3028_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_3028_DVB_T 0x0028
+
+extern struct mantis_hwconfig vp3028_config;
+
+#endif /* __MANTIS_VP3028_H */
diff --git a/drivers/media/dvb/mantis/mantis_ca.c b/drivers/media/dvb/mantis/mantis_ca.c
new file mode 100644
index 00000000000..403ce043d00
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_ca.c
@@ -0,0 +1,207 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_link.h"
+#include "mantis_hif.h"
+#include "mantis_reg.h"
+
+#include "mantis_ca.h"
+
+static int mantis_ca_read_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Read", slot);
+
+ if (slot != 0)
+ return -EINVAL;
+
+ return mantis_hif_read_mem(ca, addr);
+}
+
+static int mantis_ca_write_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr, u8 data)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Write", slot);
+
+ if (slot != 0)
+ return -EINVAL;
+
+ return mantis_hif_write_mem(ca, addr, data);
+}
+
+static int mantis_ca_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Read", slot);
+
+ if (slot != 0)
+ return -EINVAL;
+
+ return mantis_hif_read_iom(ca, addr);
+}
+
+static int mantis_ca_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr, u8 data)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Write", slot);
+
+ if (slot != 0)
+ return -EINVAL;
+
+ return mantis_hif_write_iom(ca, addr, data);
+}
+
+static int mantis_ca_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot RESET", slot);
+ udelay(500); /* Wait.. */
+ mmwrite(0xda, MANTIS_PCMCIA_RESET); /* Leading edge assert */
+ udelay(500);
+ mmwrite(0x00, MANTIS_PCMCIA_RESET); /* Trailing edge deassert */
+ msleep(1000);
+ dvb_ca_en50221_camready_irq(&ca->en50221, 0);
+
+ return 0;
+}
+
+static int mantis_ca_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot shutdown", slot);
+
+ return 0;
+}
+
+static int mantis_ts_control(struct dvb_ca_en50221 *en50221, int slot)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): TS control", slot);
+/* mantis_set_direction(mantis, 1); */ /* Enable TS through CAM */
+
+ return 0;
+}
+
+static int mantis_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Poll Slot status", slot);
+
+ if (ca->slot_state == MODULE_INSERTED) {
+ dprintk(MANTIS_DEBUG, 1, "CA Module present and ready");
+ return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
+ } else {
+ dprintk(MANTIS_DEBUG, 1, "CA Module not present or not ready");
+ }
+
+ return 0;
+}
+
+int mantis_ca_init(struct mantis_pci *mantis)
+{
+ struct dvb_adapter *dvb_adapter = &mantis->dvb_adapter;
+ struct mantis_ca *ca;
+ int ca_flags = 0, result;
+
+ dprintk(MANTIS_DEBUG, 1, "Initializing Mantis CA");
+ ca = kzalloc(sizeof(struct mantis_ca), GFP_KERNEL);
+ if (!ca) {
+ dprintk(MANTIS_ERROR, 1, "Out of memory!, exiting ..");
+ result = -ENOMEM;
+ goto err;
+ }
+
+ ca->ca_priv = mantis;
+ mantis->mantis_ca = ca;
+ ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE;
+ /* register CA interface */
+ ca->en50221.owner = THIS_MODULE;
+ ca->en50221.read_attribute_mem = mantis_ca_read_attr_mem;
+ ca->en50221.write_attribute_mem = mantis_ca_write_attr_mem;
+ ca->en50221.read_cam_control = mantis_ca_read_cam_ctl;
+ ca->en50221.write_cam_control = mantis_ca_write_cam_ctl;
+ ca->en50221.slot_reset = mantis_ca_slot_reset;
+ ca->en50221.slot_shutdown = mantis_ca_slot_shutdown;
+ ca->en50221.slot_ts_enable = mantis_ts_control;
+ ca->en50221.poll_slot_status = mantis_slot_status;
+ ca->en50221.data = ca;
+
+ mutex_init(&ca->ca_lock);
+
+ init_waitqueue_head(&ca->hif_data_wq);
+ init_waitqueue_head(&ca->hif_opdone_wq);
+ init_waitqueue_head(&ca->hif_write_wq);
+
+ dprintk(MANTIS_ERROR, 1, "Registering EN50221 device");
+ result = dvb_ca_en50221_init(dvb_adapter, &ca->en50221, ca_flags, 1);
+ if (result != 0) {
+ dprintk(MANTIS_ERROR, 1, "EN50221: Initialization failed <%d>", result);
+ goto err;
+ }
+ dprintk(MANTIS_ERROR, 1, "Registered EN50221 device");
+ mantis_evmgr_init(ca);
+ return 0;
+err:
+ kfree(ca);
+ return result;
+}
+EXPORT_SYMBOL_GPL(mantis_ca_init);
+
+void mantis_ca_exit(struct mantis_pci *mantis)
+{
+ struct mantis_ca *ca = mantis->mantis_ca;
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis CA exit");
+
+ mantis_evmgr_exit(ca);
+ dprintk(MANTIS_ERROR, 1, "Unregistering EN50221 device");
+ if (ca)
+ dvb_ca_en50221_release(&ca->en50221);
+
+ kfree(ca);
+}
+EXPORT_SYMBOL_GPL(mantis_ca_exit);
diff --git a/drivers/media/dvb/mantis/mantis_ca.h b/drivers/media/dvb/mantis/mantis_ca.h
new file mode 100644
index 00000000000..dc63e55f7ec
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_ca.h
@@ -0,0 +1,27 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MANTIS_CA_H
+#define __MANTIS_CA_H
+
+extern int mantis_ca_init(struct mantis_pci *mantis);
+extern void mantis_ca_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_CA_H */
diff --git a/drivers/media/dvb/mantis/mantis_cards.c b/drivers/media/dvb/mantis/mantis_cards.c
new file mode 100644
index 00000000000..16f1708fd3b
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_cards.c
@@ -0,0 +1,305 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <asm/irq.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+
+#include "mantis_vp1033.h"
+#include "mantis_vp1034.h"
+#include "mantis_vp1041.h"
+#include "mantis_vp2033.h"
+#include "mantis_vp2040.h"
+#include "mantis_vp3030.h"
+
+#include "mantis_dma.h"
+#include "mantis_ca.h"
+#include "mantis_dvb.h"
+#include "mantis_uart.h"
+#include "mantis_ioc.h"
+#include "mantis_pci.h"
+#include "mantis_i2c.h"
+#include "mantis_reg.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
+
+static int devs;
+
+#define DRIVER_NAME "Mantis"
+
+static char *label[10] = {
+ "DMA",
+ "IRQ-0",
+ "IRQ-1",
+ "OCERR",
+ "PABRT",
+ "RIPRR",
+ "PPERR",
+ "FTRGT",
+ "RISCI",
+ "RACK"
+};
+
+static irqreturn_t mantis_irq_handler(int irq, void *dev_id)
+{
+ u32 stat = 0, mask = 0, lstat = 0, mstat = 0;
+ u32 rst_stat = 0, rst_mask = 0;
+
+ struct mantis_pci *mantis;
+ struct mantis_ca *ca;
+
+ mantis = (struct mantis_pci *) dev_id;
+ if (unlikely(mantis == NULL)) {
+ dprintk(MANTIS_ERROR, 1, "Mantis == NULL");
+ return IRQ_NONE;
+ }
+ ca = mantis->mantis_ca;
+
+ stat = mmread(MANTIS_INT_STAT);
+ mask = mmread(MANTIS_INT_MASK);
+ mstat = lstat = stat & ~MANTIS_INT_RISCSTAT;
+ if (!(stat & mask))
+ return IRQ_NONE;
+
+ rst_mask = MANTIS_GPIF_WRACK |
+ MANTIS_GPIF_OTHERR |
+ MANTIS_SBUF_WSTO |
+ MANTIS_GPIF_EXTIRQ;
+
+ rst_stat = mmread(MANTIS_GPIF_STATUS);
+ rst_stat &= rst_mask;
+ mmwrite(rst_stat, MANTIS_GPIF_STATUS);
+
+ mantis->mantis_int_stat = stat;
+ mantis->mantis_int_mask = mask;
+ dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask);
+ if (stat & MANTIS_INT_RISCEN) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]);
+ }
+ if (stat & MANTIS_INT_IRQ0) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]);
+ mantis->gpif_status = rst_stat;
+ wake_up(&ca->hif_write_wq);
+ schedule_work(&ca->hif_evm_work);
+ }
+ if (stat & MANTIS_INT_IRQ1) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]);
+ schedule_work(&mantis->uart_work);
+ }
+ if (stat & MANTIS_INT_OCERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]);
+ }
+ if (stat & MANTIS_INT_PABORT) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]);
+ }
+ if (stat & MANTIS_INT_RIPERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]);
+ }
+ if (stat & MANTIS_INT_PPERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]);
+ }
+ if (stat & MANTIS_INT_FTRGT) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]);
+ }
+ if (stat & MANTIS_INT_RISCI) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
+ mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
+ tasklet_schedule(&mantis->tasklet);
+ }
+ if (stat & MANTIS_INT_I2CDONE) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);
+ wake_up(&mantis->i2c_wq);
+ }
+ mmwrite(stat, MANTIS_INT_STAT);
+ stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE |
+ MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 |
+ MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 |
+ MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 |
+ MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 |
+ MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 |
+ MANTIS_INT_IRQ0 | MANTIS_INT_OCERR |
+ MANTIS_INT_PABORT | MANTIS_INT_RIPERR |
+ MANTIS_INT_PPERR | MANTIS_INT_FTRGT |
+ MANTIS_INT_RISCI);
+
+ if (stat)
+ dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>", stat, mask);
+
+ dprintk(MANTIS_DEBUG, 0, "\n");
+ return IRQ_HANDLED;
+}
+
+static int __devinit mantis_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+{
+ struct mantis_pci *mantis;
+ struct mantis_hwconfig *config;
+ int err = 0;
+
+ mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL);
+ if (mantis == NULL) {
+ printk(KERN_ERR "%s ERROR: Out of memory\n", __func__);
+ err = -ENOMEM;
+ goto fail0;
+ }
+
+ mantis->num = devs;
+ mantis->verbose = verbose;
+ mantis->pdev = pdev;
+ config = (struct mantis_hwconfig *) pci_id->driver_data;
+ config->irq_handler = &mantis_irq_handler;
+ mantis->hwconfig = config;
+
+ err = mantis_pci_init(mantis);
+ if (err) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err);
+ goto fail1;
+ }
+
+ err = mantis_stream_control(mantis, STREAM_TO_HIF);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err);
+ goto fail1;
+ }
+
+ err = mantis_i2c_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err);
+ goto fail2;
+ }
+
+ err = mantis_get_mac(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err);
+ goto fail2;
+ }
+
+ err = mantis_dma_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err);
+ goto fail3;
+ }
+
+ err = mantis_dvb_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err);
+ goto fail4;
+ }
+ err = mantis_uart_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART initialization failed <%d>", err);
+ goto fail6;
+ }
+
+ devs++;
+
+ return err;
+
+
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART exit! <%d>", err);
+ mantis_uart_exit(mantis);
+
+fail6:
+fail4:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err);
+ mantis_dma_exit(mantis);
+
+fail3:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err);
+ mantis_i2c_exit(mantis);
+
+fail2:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err);
+ mantis_pci_exit(mantis);
+
+fail1:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err);
+ kfree(mantis);
+
+fail0:
+ return err;
+}
+
+static void __devexit mantis_pci_remove(struct pci_dev *pdev)
+{
+ struct mantis_pci *mantis = pci_get_drvdata(pdev);
+
+ if (mantis) {
+
+ mantis_uart_exit(mantis);
+ mantis_dvb_exit(mantis);
+ mantis_dma_exit(mantis);
+ mantis_i2c_exit(mantis);
+ mantis_pci_exit(mantis);
+ kfree(mantis);
+ }
+ return;
+}
+
+static struct pci_device_id mantis_pci_table[] = {
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1033_DVB_S, &vp1033_config),
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1034_DVB_S, &vp1034_config),
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1041_DVB_S2, &vp1041_config),
+ MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_10, &vp1041_config),
+ MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_20, &vp1041_config),
+ MAKE_ENTRY(TERRATEC, CINERGY_S2_PCI_HD, &vp1041_config),
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2033_DVB_C, &vp2033_config),
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2040_DVB_C, &vp2040_config),
+ MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config),
+ MAKE_ENTRY(TERRATEC, CINERGY_C, &vp2033_config),
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3030_DVB_T, &vp3030_config),
+ { }
+};
+
+static struct pci_driver mantis_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = mantis_pci_table,
+ .probe = mantis_pci_probe,
+ .remove = mantis_pci_remove,
+};
+
+static int __devinit mantis_init(void)
+{
+ return pci_register_driver(&mantis_pci_driver);
+}
+
+static void __devexit mantis_exit(void)
+{
+ return pci_unregister_driver(&mantis_pci_driver);
+}
+
+module_init(mantis_init);
+module_exit(mantis_exit);
+
+MODULE_DESCRIPTION("MANTIS driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/mantis/mantis_common.h b/drivers/media/dvb/mantis/mantis_common.h
new file mode 100644
index 00000000000..d0b645a483c
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_common.h
@@ -0,0 +1,179 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MANTIS_COMMON_H
+#define __MANTIS_COMMON_H
+
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+#include "mantis_uart.h"
+
+#include "mantis_link.h"
+
+#define MANTIS_ERROR 0
+#define MANTIS_NOTICE 1
+#define MANTIS_INFO 2
+#define MANTIS_DEBUG 3
+#define MANTIS_TMG 9
+
+#define dprintk(y, z, format, arg...) do { \
+ if (z) { \
+ if ((mantis->verbose > MANTIS_ERROR) && (mantis->verbose > y)) \
+ printk(KERN_ERR "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \
+ else if ((mantis->verbose > MANTIS_NOTICE) && (mantis->verbose > y)) \
+ printk(KERN_NOTICE "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \
+ else if ((mantis->verbose > MANTIS_INFO) && (mantis->verbose > y)) \
+ printk(KERN_INFO "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \
+ else if ((mantis->verbose > MANTIS_DEBUG) && (mantis->verbose > y)) \
+ printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \
+ else if ((mantis->verbose > MANTIS_TMG) && (mantis->verbose > y)) \
+ printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \
+ } else { \
+ if (mantis->verbose > y) \
+ printk(format , ##arg); \
+ } \
+} while(0)
+
+#define mwrite(dat, addr) writel((dat), addr)
+#define mread(addr) readl(addr)
+
+#define mmwrite(dat, addr) mwrite((dat), (mantis->mmio + (addr)))
+#define mmread(addr) mread(mantis->mmio + (addr))
+
+#define MANTIS_TS_188 0
+#define MANTIS_TS_204 1
+
+#define TWINHAN_TECHNOLOGIES 0x1822
+#define MANTIS 0x4e35
+
+#define TECHNISAT 0x1ae4
+#define TERRATEC 0x153b
+
+#define MAKE_ENTRY(__subven, __subdev, __configptr) { \
+ .vendor = TWINHAN_TECHNOLOGIES, \
+ .device = MANTIS, \
+ .subvendor = (__subven), \
+ .subdevice = (__subdev), \
+ .driver_data = (unsigned long) (__configptr) \
+}
+
+enum mantis_i2c_mode {
+ MANTIS_PAGE_MODE = 0,
+ MANTIS_BYTE_MODE,
+};
+
+struct mantis_pci;
+
+struct mantis_hwconfig {
+ char *model_name;
+ char *dev_type;
+ u32 ts_size;
+
+ enum mantis_baud baud_rate;
+ enum mantis_parity parity;
+ u32 bytes;
+
+ irqreturn_t (*irq_handler)(int irq, void *dev_id);
+ int (*frontend_init)(struct mantis_pci *mantis, struct dvb_frontend *fe);
+
+ u8 power;
+ u8 reset;
+
+ enum mantis_i2c_mode i2c_mode;
+};
+
+struct mantis_pci {
+ unsigned int verbose;
+
+ /* PCI stuff */
+ u16 vendor_id;
+ u16 device_id;
+ u16 subsystem_vendor;
+ u16 subsystem_device;
+
+ u8 latency;
+
+ struct pci_dev *pdev;
+
+ unsigned long mantis_addr;
+ void __iomem *mmio;
+
+ u8 irq;
+ u8 revision;
+
+ unsigned int num;
+
+ /* RISC Core */
+ u32 finished_block;
+ u32 last_block;
+ u32 line_bytes;
+ u32 line_count;
+ u32 risc_pos;
+ u8 *buf_cpu;
+ dma_addr_t buf_dma;
+ u32 *risc_cpu;
+ dma_addr_t risc_dma;
+
+ struct tasklet_struct tasklet;
+
+ struct i2c_adapter adapter;
+ int i2c_rc;
+ wait_queue_head_t i2c_wq;
+ struct mutex i2c_lock;
+
+ /* DVB stuff */
+ struct dvb_adapter dvb_adapter;
+ struct dvb_frontend *fe;
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ struct dmx_frontend fe_hw;
+ struct dmx_frontend fe_mem;
+ struct dvb_net dvbnet;
+
+ u8 feeds;
+
+ struct mantis_hwconfig *hwconfig;
+
+ u32 mantis_int_stat;
+ u32 mantis_int_mask;
+
+ /* board specific */
+ u8 mac_address[8];
+ u32 sub_vendor_id;
+ u32 sub_device_id;
+
+ /* A12 A13 A14 */
+ u32 gpio_status;
+
+ u32 gpif_status;
+
+ struct mantis_ca *mantis_ca;
+
+ wait_queue_head_t uart_wq;
+ struct work_struct uart_work;
+ spinlock_t uart_lock;
+
+ struct input_dev *rc;
+};
+
+#define MANTIS_HIF_STATUS (mantis->gpio_status)
+
+#endif /* __MANTIS_COMMON_H */
diff --git a/drivers/media/dvb/mantis/mantis_core.c b/drivers/media/dvb/mantis/mantis_core.c
new file mode 100644
index 00000000000..8113b23ce44
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_core.c
@@ -0,0 +1,238 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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 "mantis_common.h"
+#include "mantis_core.h"
+#include "mantis_vp1033.h"
+#include "mantis_vp1034.h"
+#include "mantis_vp1041.h"
+#include "mantis_vp2033.h"
+#include "mantis_vp2040.h"
+#include "mantis_vp3030.h"
+
+static int read_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
+{
+ int err;
+ struct i2c_msg msg[] = {
+ {
+ .addr = 0x50,
+ .flags = 0,
+ .buf = data,
+ .len = 1
+ }, {
+ .addr = 0x50,
+ .flags = I2C_M_RD,
+ .buf = data,
+ .len = length
+ },
+ };
+
+ err = i2c_transfer(&mantis->adapter, msg, 2);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1,
+ "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >",
+ err, data[0], data[1]);
+
+ return err;
+ }
+
+ return 0;
+}
+
+static int write_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
+{
+ int err;
+
+ struct i2c_msg msg = {
+ .addr = 0x50,
+ .flags = 0,
+ .buf = data,
+ .len = length
+ };
+
+ err = i2c_transfer(&mantis->adapter, &msg, 1);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1,
+ "ERROR: i2c write: < err=%i length=0x%02x d0=0x%02x, d1=0x%02x >",
+ err, length, data[0], data[1]);
+
+ return err;
+ }
+
+ return 0;
+}
+
+static int get_mac_address(struct mantis_pci *mantis)
+{
+ int err;
+
+ mantis->mac_address[0] = 0x08;
+ err = read_eeprom_byte(mantis, &mantis->mac_address[0], 6);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1, "Mantis EEPROM read error");
+
+ return err;
+ }
+ dprintk(verbose, MANTIS_ERROR, 0,
+ " MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]\n",
+ mantis->mac_address[0], mantis->mac_address[1],
+ mantis->mac_address[2], mantis->mac_address[3],
+ mantis->mac_address[4], mantis->mac_address[5]);
+
+ return 0;
+}
+
+#define MANTIS_MODEL_UNKNOWN "UNKNOWN"
+#define MANTIS_DEV_UNKNOWN "UNKNOWN"
+
+struct mantis_hwconfig unknown_device = {
+ .model_name = MANTIS_MODEL_UNKNOWN,
+ .dev_type = MANTIS_DEV_UNKNOWN,
+};
+
+static void mantis_load_config(struct mantis_pci *mantis)
+{
+ switch (mantis->subsystem_device) {
+ case MANTIS_VP_1033_DVB_S: /* VP-1033 */
+ mantis->hwconfig = &vp1033_mantis_config;
+ break;
+ case MANTIS_VP_1034_DVB_S: /* VP-1034 */
+ mantis->hwconfig = &vp1034_mantis_config;
+ break;
+ case MANTIS_VP_1041_DVB_S2: /* VP-1041 */
+ case TECHNISAT_SKYSTAR_HD2:
+ mantis->hwconfig = &vp1041_mantis_config;
+ break;
+ case MANTIS_VP_2033_DVB_C: /* VP-2033 */
+ mantis->hwconfig = &vp2033_mantis_config;
+ break;
+ case MANTIS_VP_2040_DVB_C: /* VP-2040 */
+ case TERRATEC_CINERGY_C_PCI: /* VP-2040 clone */
+ case TECHNISAT_CABLESTAR_HD2:
+ mantis->hwconfig = &vp2040_mantis_config;
+ break;
+ case MANTIS_VP_3030_DVB_T: /* VP-3030 */
+ mantis->hwconfig = &vp3030_mantis_config;
+ break;
+ default:
+ mantis->hwconfig = &unknown_device;
+ break;
+ }
+}
+
+int mantis_core_init(struct mantis_pci *mantis)
+{
+ int err = 0;
+
+ mantis_load_config(mantis);
+ dprintk(verbose, MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n",
+ mantis->hwconfig->model_name, mantis->hwconfig->dev_type,
+ mantis->pdev->bus->number, PCI_SLOT(mantis->pdev->devfn), PCI_FUNC(mantis->pdev->devfn));
+ dprintk(verbose, MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ",
+ mantis->revision,
+ mantis->subsystem_vendor, mantis->subsystem_device);
+ dprintk(verbose, MANTIS_ERROR, 0,
+ "irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n",
+ mantis->pdev->irq, mantis->latency,
+ mantis->mantis_addr, mantis->mantis_mmio);
+
+ err = mantis_i2c_init(mantis);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1, "Mantis I2C init failed");
+ return err;
+ }
+ err = get_mac_address(mantis);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1, "get MAC address failed");
+ return err;
+ }
+ err = mantis_dma_init(mantis);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1, "Mantis DMA init failed");
+ return err;
+ }
+ err = mantis_dvb_init(mantis);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DVB init failed");
+ return err;
+ }
+ err = mantis_uart_init(mantis);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_DEBUG, 1, "Mantis UART init failed");
+ return err;
+ }
+
+ return 0;
+}
+
+int mantis_core_exit(struct mantis_pci *mantis)
+{
+ mantis_dma_stop(mantis);
+ dprintk(verbose, MANTIS_ERROR, 1, "DMA engine stopping");
+
+ mantis_uart_exit(mantis);
+ dprintk(verbose, MANTIS_ERROR, 1, "UART exit failed");
+
+ if (mantis_dma_exit(mantis) < 0)
+ dprintk(verbose, MANTIS_ERROR, 1, "DMA exit failed");
+ if (mantis_dvb_exit(mantis) < 0)
+ dprintk(verbose, MANTIS_ERROR, 1, "DVB exit failed");
+ if (mantis_i2c_exit(mantis) < 0)
+ dprintk(verbose, MANTIS_ERROR, 1, "I2C adapter delete.. failed");
+
+ return 0;
+}
+
+/* Turn the given bit on or off. */
+void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
+{
+ u32 cur;
+
+ cur = mmread(MANTIS_GPIF_ADDR);
+ if (value)
+ mantis->gpio_status = cur | (1 << bitpos);
+ else
+ mantis->gpio_status = cur & (~(1 << bitpos));
+
+ mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR);
+ mmwrite(0x00, MANTIS_GPIF_DOUT);
+ udelay(100);
+}
+
+/* direction = 0 , no CI passthrough ; 1 , CI passthrough */
+void mantis_set_direction(struct mantis_pci *mantis, int direction)
+{
+ u32 reg;
+
+ reg = mmread(0x28);
+ dprintk(verbose, MANTIS_DEBUG, 1, "TS direction setup");
+ if (direction == 0x01) {
+ /* to CI */
+ reg |= 0x04;
+ mmwrite(reg, 0x28);
+ reg &= 0xff - 0x04;
+ mmwrite(reg, 0x28);
+ } else {
+ reg &= 0xff - 0x04;
+ mmwrite(reg, 0x28);
+ reg |= 0x04;
+ mmwrite(reg, 0x28);
+ }
+}
diff --git a/drivers/media/dvb/mantis/mantis_core.h b/drivers/media/dvb/mantis/mantis_core.h
new file mode 100644
index 00000000000..833ee42e694
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_core.h
@@ -0,0 +1,57 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MANTIS_CORE_H
+#define __MANTIS_CORE_H
+
+#include "mantis_common.h"
+
+
+#define FE_TYPE_SAT 0
+#define FE_TYPE_CAB 1
+#define FE_TYPE_TER 2
+
+#define FE_TYPE_TS204 0
+#define FE_TYPE_TS188 1
+
+
+struct vendorname {
+ u8 *sub_vendor_name;
+ u32 sub_vendor_id;
+};
+
+struct devicetype {
+ u8 *sub_device_name;
+ u32 sub_device_id;
+ u8 device_type;
+ u32 type_flags;
+};
+
+
+extern int mantis_dma_init(struct mantis_pci *mantis);
+extern int mantis_dma_exit(struct mantis_pci *mantis);
+extern void mantis_dma_start(struct mantis_pci *mantis);
+extern void mantis_dma_stop(struct mantis_pci *mantis);
+extern int mantis_i2c_init(struct mantis_pci *mantis);
+extern int mantis_i2c_exit(struct mantis_pci *mantis);
+extern int mantis_core_init(struct mantis_pci *mantis);
+extern int mantis_core_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_CORE_H */
diff --git a/drivers/media/dvb/mantis/mantis_dma.c b/drivers/media/dvb/mantis/mantis_dma.c
new file mode 100644
index 00000000000..46202a4012a
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_dma.c
@@ -0,0 +1,256 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/kernel.h>
+#include <asm/page.h>
+#include <linux/vmalloc.h>
+#include <linux/pci.h>
+
+#include <asm/irq.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_dma.h"
+
+#define RISC_WRITE (0x01 << 28)
+#define RISC_JUMP (0x07 << 28)
+#define RISC_IRQ (0x01 << 24)
+
+#define RISC_STATUS(status) ((((~status) & 0x0f) << 20) | ((status & 0x0f) << 16))
+#define RISC_FLUSH() (mantis->risc_pos = 0)
+#define RISC_INSTR(opcode) (mantis->risc_cpu[mantis->risc_pos++] = cpu_to_le32(opcode))
+
+#define MANTIS_BUF_SIZE (64 * 1024)
+#define MANTIS_BLOCK_BYTES (MANTIS_BUF_SIZE >> 4)
+#define MANTIS_BLOCK_COUNT (1 << 4)
+#define MANTIS_RISC_SIZE PAGE_SIZE
+
+int mantis_dma_exit(struct mantis_pci *mantis)
+{
+ if (mantis->buf_cpu) {
+ dprintk(MANTIS_ERROR, 1,
+ "DMA=0x%lx cpu=0x%p size=%d",
+ (unsigned long) mantis->buf_dma,
+ mantis->buf_cpu,
+ MANTIS_BUF_SIZE);
+
+ pci_free_consistent(mantis->pdev, MANTIS_BUF_SIZE,
+ mantis->buf_cpu, mantis->buf_dma);
+
+ mantis->buf_cpu = NULL;
+ }
+ if (mantis->risc_cpu) {
+ dprintk(MANTIS_ERROR, 1,
+ "RISC=0x%lx cpu=0x%p size=%lx",
+ (unsigned long) mantis->risc_dma,
+ mantis->risc_cpu,
+ MANTIS_RISC_SIZE);
+
+ pci_free_consistent(mantis->pdev, MANTIS_RISC_SIZE,
+ mantis->risc_cpu, mantis->risc_dma);
+
+ mantis->risc_cpu = NULL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_dma_exit);
+
+static inline int mantis_alloc_buffers(struct mantis_pci *mantis)
+{
+ if (!mantis->buf_cpu) {
+ mantis->buf_cpu = pci_alloc_consistent(mantis->pdev,
+ MANTIS_BUF_SIZE,
+ &mantis->buf_dma);
+ if (!mantis->buf_cpu) {
+ dprintk(MANTIS_ERROR, 1,
+ "DMA buffer allocation failed");
+
+ goto err;
+ }
+ dprintk(MANTIS_ERROR, 1,
+ "DMA=0x%lx cpu=0x%p size=%d",
+ (unsigned long) mantis->buf_dma,
+ mantis->buf_cpu, MANTIS_BUF_SIZE);
+ }
+ if (!mantis->risc_cpu) {
+ mantis->risc_cpu = pci_alloc_consistent(mantis->pdev,
+ MANTIS_RISC_SIZE,
+ &mantis->risc_dma);
+
+ if (!mantis->risc_cpu) {
+ dprintk(MANTIS_ERROR, 1,
+ "RISC program allocation failed");
+
+ mantis_dma_exit(mantis);
+
+ goto err;
+ }
+ dprintk(MANTIS_ERROR, 1,
+ "RISC=0x%lx cpu=0x%p size=%lx",
+ (unsigned long) mantis->risc_dma,
+ mantis->risc_cpu, MANTIS_RISC_SIZE);
+ }
+
+ return 0;
+err:
+ dprintk(MANTIS_ERROR, 1, "Out of memory (?) .....");
+ return -ENOMEM;
+}
+
+static inline int mantis_calc_lines(struct mantis_pci *mantis)
+{
+ mantis->line_bytes = MANTIS_BLOCK_BYTES;
+ mantis->line_count = MANTIS_BLOCK_COUNT;
+
+ while (mantis->line_bytes > 4095) {
+ mantis->line_bytes >>= 1;
+ mantis->line_count <<= 1;
+ }
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis RISC block bytes=[%d], line bytes=[%d], line count=[%d]",
+ MANTIS_BLOCK_BYTES, mantis->line_bytes, mantis->line_count);
+
+ if (mantis->line_count > 255) {
+ dprintk(MANTIS_ERROR, 1, "Buffer size error");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int mantis_dma_init(struct mantis_pci *mantis)
+{
+ int err = 0;
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis DMA init");
+ if (mantis_alloc_buffers(mantis) < 0) {
+ dprintk(MANTIS_ERROR, 1, "Error allocating DMA buffer");
+
+ /* Stop RISC Engine */
+ mmwrite(0, MANTIS_DMA_CTL);
+
+ goto err;
+ }
+ err = mantis_calc_lines(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "Mantis calc lines failed");
+
+ goto err;
+ }
+
+ return 0;
+err:
+ return err;
+}
+EXPORT_SYMBOL_GPL(mantis_dma_init);
+
+static inline void mantis_risc_program(struct mantis_pci *mantis)
+{
+ u32 buf_pos = 0;
+ u32 line;
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis create RISC program");
+ RISC_FLUSH();
+
+ dprintk(MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u",
+ mantis->line_count, mantis->line_bytes);
+
+ for (line = 0; line < mantis->line_count; line++) {
+ dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d]", line);
+ if (!(buf_pos % MANTIS_BLOCK_BYTES)) {
+ RISC_INSTR(RISC_WRITE |
+ RISC_IRQ |
+ RISC_STATUS(((buf_pos / MANTIS_BLOCK_BYTES) +
+ (MANTIS_BLOCK_COUNT - 1)) %
+ MANTIS_BLOCK_COUNT) |
+ mantis->line_bytes);
+ } else {
+ RISC_INSTR(RISC_WRITE | mantis->line_bytes);
+ }
+ RISC_INSTR(mantis->buf_dma + buf_pos);
+ buf_pos += mantis->line_bytes;
+ }
+ RISC_INSTR(RISC_JUMP);
+ RISC_INSTR(mantis->risc_dma);
+}
+
+void mantis_dma_start(struct mantis_pci *mantis)
+{
+ dprintk(MANTIS_DEBUG, 1, "Mantis Start DMA engine");
+
+ mantis_risc_program(mantis);
+ mmwrite(mantis->risc_dma, MANTIS_RISC_START);
+ mmwrite(mmread(MANTIS_GPIF_ADDR) | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR);
+
+ mmwrite(0, MANTIS_DMA_CTL);
+ mantis->last_block = mantis->finished_block = 0;
+
+ mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_RISCI, MANTIS_INT_MASK);
+
+ mmwrite(MANTIS_FIFO_EN | MANTIS_DCAP_EN
+ | MANTIS_RISC_EN, MANTIS_DMA_CTL);
+
+}
+
+void mantis_dma_stop(struct mantis_pci *mantis)
+{
+ u32 stat = 0, mask = 0;
+
+ stat = mmread(MANTIS_INT_STAT);
+ mask = mmread(MANTIS_INT_MASK);
+ dprintk(MANTIS_DEBUG, 1, "Mantis Stop DMA engine");
+
+ mmwrite((mmread(MANTIS_GPIF_ADDR) & (~(MANTIS_GPIF_HIFRDWRN))), MANTIS_GPIF_ADDR);
+
+ mmwrite((mmread(MANTIS_DMA_CTL) & ~(MANTIS_FIFO_EN |
+ MANTIS_DCAP_EN |
+ MANTIS_RISC_EN)), MANTIS_DMA_CTL);
+
+ mmwrite(mmread(MANTIS_INT_STAT), MANTIS_INT_STAT);
+
+ mmwrite(mmread(MANTIS_INT_MASK) & ~(MANTIS_INT_RISCI |
+ MANTIS_INT_RISCEN), MANTIS_INT_MASK);
+}
+
+
+void mantis_dma_xfer(unsigned long data)
+{
+ struct mantis_pci *mantis = (struct mantis_pci *) data;
+ struct mantis_hwconfig *config = mantis->hwconfig;
+
+ while (mantis->last_block != mantis->finished_block) {
+ dprintk(MANTIS_DEBUG, 1, "last block=[%d] finished block=[%d]",
+ mantis->last_block, mantis->finished_block);
+
+ (config->ts_size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter)
+ (&mantis->demux, &mantis->buf_cpu[mantis->last_block * MANTIS_BLOCK_BYTES], MANTIS_BLOCK_BYTES);
+ mantis->last_block = (mantis->last_block + 1) % MANTIS_BLOCK_COUNT;
+ }
+}
diff --git a/drivers/media/dvb/mantis/mantis_dma.h b/drivers/media/dvb/mantis/mantis_dma.h
new file mode 100644
index 00000000000..6be00fa8209
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_dma.h
@@ -0,0 +1,30 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MANTIS_DMA_H
+#define __MANTIS_DMA_H
+
+extern int mantis_dma_init(struct mantis_pci *mantis);
+extern int mantis_dma_exit(struct mantis_pci *mantis);
+extern void mantis_dma_start(struct mantis_pci *mantis);
+extern void mantis_dma_stop(struct mantis_pci *mantis);
+extern void mantis_dma_xfer(unsigned long data);
+
+#endif /* __MANTIS_DMA_H */
diff --git a/drivers/media/dvb/mantis/mantis_dvb.c b/drivers/media/dvb/mantis/mantis_dvb.c
new file mode 100644
index 00000000000..99d82eec3b0
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_dvb.c
@@ -0,0 +1,296 @@
+/*
+ Mantis PCI bridge driver
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/kernel.h>
+#include <linux/bitops.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_dma.h"
+#include "mantis_ca.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power)
+{
+ struct mantis_hwconfig *config = mantis->hwconfig;
+
+ switch (power) {
+ case POWER_ON:
+ dprintk(MANTIS_DEBUG, 1, "Power ON");
+ gpio_set_bits(mantis, config->power, POWER_ON);
+ msleep(100);
+ gpio_set_bits(mantis, config->power, POWER_ON);
+ msleep(100);
+ break;
+
+ case POWER_OFF:
+ dprintk(MANTIS_DEBUG, 1, "Power OFF");
+ gpio_set_bits(mantis, config->power, POWER_OFF);
+ msleep(100);
+ break;
+
+ default:
+ dprintk(MANTIS_DEBUG, 1, "Unknown state <%02x>", power);
+ return -1;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_frontend_power);
+
+void mantis_frontend_soft_reset(struct mantis_pci *mantis)
+{
+ struct mantis_hwconfig *config = mantis->hwconfig;
+
+ dprintk(MANTIS_DEBUG, 1, "Frontend RESET");
+ gpio_set_bits(mantis, config->reset, 0);
+ msleep(100);
+ gpio_set_bits(mantis, config->reset, 0);
+ msleep(100);
+ gpio_set_bits(mantis, config->reset, 1);
+ msleep(100);
+ gpio_set_bits(mantis, config->reset, 1);
+ msleep(100);
+
+ return;
+}
+EXPORT_SYMBOL_GPL(mantis_frontend_soft_reset);
+
+static int mantis_frontend_shutdown(struct mantis_pci *mantis)
+{
+ int err;
+
+ mantis_frontend_soft_reset(mantis);
+ err = mantis_frontend_power(mantis, POWER_OFF);
+ if (err != 0) {
+ dprintk(MANTIS_ERROR, 1, "Frontend POWER OFF failed! <%d>", err);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+ struct mantis_pci *mantis = dvbdmx->priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis DVB Start feed");
+ if (!dvbdmx->dmx.frontend) {
+ dprintk(MANTIS_DEBUG, 1, "no frontend ?");
+ return -EINVAL;
+ }
+
+ mantis->feeds++;
+ dprintk(MANTIS_DEBUG, 1, "mantis start feed, feeds=%d", mantis->feeds);
+
+ if (mantis->feeds == 1) {
+ dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma");
+ mantis_dma_start(mantis);
+ }
+
+ return mantis->feeds;
+}
+
+static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+ struct mantis_pci *mantis = dvbdmx->priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis DVB Stop feed");
+ if (!dvbdmx->dmx.frontend) {
+ dprintk(MANTIS_DEBUG, 1, "no frontend ?");
+ return -EINVAL;
+ }
+
+ mantis->feeds--;
+ if (mantis->feeds == 0) {
+ dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma");
+ mantis_dma_stop(mantis);
+ }
+
+ return 0;
+}
+
+int __devinit mantis_dvb_init(struct mantis_pci *mantis)
+{
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ int result = -1;
+
+ dprintk(MANTIS_DEBUG, 1, "dvb_register_adapter");
+
+ result = dvb_register_adapter(&mantis->dvb_adapter,
+ "Mantis DVB adapter",
+ THIS_MODULE,
+ &mantis->pdev->dev,
+ adapter_nr);
+
+ if (result < 0) {
+
+ dprintk(MANTIS_ERROR, 1, "Error registering adapter");
+ return -ENODEV;
+ }
+
+ mantis->dvb_adapter.priv = mantis;
+ mantis->demux.dmx.capabilities = DMX_TS_FILTERING |
+ DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING;
+
+ mantis->demux.priv = mantis;
+ mantis->demux.filternum = 256;
+ mantis->demux.feednum = 256;
+ mantis->demux.start_feed = mantis_dvb_start_feed;
+ mantis->demux.stop_feed = mantis_dvb_stop_feed;
+ mantis->demux.write_to_decoder = NULL;
+
+ dprintk(MANTIS_DEBUG, 1, "dvb_dmx_init");
+ result = dvb_dmx_init(&mantis->demux);
+ if (result < 0) {
+ dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+
+ goto err0;
+ }
+
+ mantis->dmxdev.filternum = 256;
+ mantis->dmxdev.demux = &mantis->demux.dmx;
+ mantis->dmxdev.capabilities = 0;
+ dprintk(MANTIS_DEBUG, 1, "dvb_dmxdev_init");
+
+ result = dvb_dmxdev_init(&mantis->dmxdev, &mantis->dvb_adapter);
+ if (result < 0) {
+
+ dprintk(MANTIS_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result);
+ goto err1;
+ }
+
+ mantis->fe_hw.source = DMX_FRONTEND_0;
+ result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+ if (result < 0) {
+
+ dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+ goto err2;
+ }
+
+ mantis->fe_mem.source = DMX_MEMORY_FE;
+ result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_mem);
+ if (result < 0) {
+ dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+ goto err3;
+ }
+
+ result = mantis->demux.dmx.connect_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+ if (result < 0) {
+ dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+ goto err4;
+ }
+
+ dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx);
+ tasklet_init(&mantis->tasklet, mantis_dma_xfer, (unsigned long) mantis);
+ if (mantis->hwconfig) {
+ result = config->frontend_init(mantis, mantis->fe);
+ if (result < 0) {
+ dprintk(MANTIS_ERROR, 1, "!!! NO Frontends found !!!");
+ goto err5;
+ } else {
+ if (mantis->fe == NULL) {
+ dprintk(MANTIS_ERROR, 1, "FE <NULL>");
+ goto err5;
+ }
+
+ if (dvb_register_frontend(&mantis->dvb_adapter, mantis->fe)) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Frontend registration failed");
+
+ if (mantis->fe->ops.release)
+ mantis->fe->ops.release(mantis->fe);
+
+ mantis->fe = NULL;
+ goto err5;
+ }
+ }
+ }
+
+ return 0;
+
+ /* Error conditions .. */
+err5:
+ tasklet_kill(&mantis->tasklet);
+ dvb_net_release(&mantis->dvbnet);
+ dvb_unregister_frontend(mantis->fe);
+ dvb_frontend_detach(mantis->fe);
+err4:
+ mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
+
+err3:
+ mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+
+err2:
+ dvb_dmxdev_release(&mantis->dmxdev);
+
+err1:
+ dvb_dmx_release(&mantis->demux);
+
+err0:
+ dvb_unregister_adapter(&mantis->dvb_adapter);
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(mantis_dvb_init);
+
+int __devexit mantis_dvb_exit(struct mantis_pci *mantis)
+{
+ int err;
+
+ if (mantis->fe) {
+ /* mantis_ca_exit(mantis); */
+ err = mantis_frontend_shutdown(mantis);
+ if (err != 0)
+ dprintk(MANTIS_ERROR, 1, "Frontend exit while POWER ON! <%d>", err);
+ dvb_unregister_frontend(mantis->fe);
+ dvb_frontend_detach(mantis->fe);
+ }
+
+ tasklet_kill(&mantis->tasklet);
+ dvb_net_release(&mantis->dvbnet);
+
+ mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
+ mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+
+ dvb_dmxdev_release(&mantis->dmxdev);
+ dvb_dmx_release(&mantis->demux);
+
+ dprintk(MANTIS_DEBUG, 1, "dvb_unregister_adapter");
+ dvb_unregister_adapter(&mantis->dvb_adapter);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_dvb_exit);
diff --git a/drivers/media/dvb/mantis/mantis_dvb.h b/drivers/media/dvb/mantis/mantis_dvb.h
new file mode 100644
index 00000000000..464199db304
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_dvb.h
@@ -0,0 +1,35 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MANTIS_DVB_H
+#define __MANTIS_DVB_H
+
+enum mantis_power {
+ POWER_OFF = 0,
+ POWER_ON = 1
+};
+
+extern int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power);
+extern void mantis_frontend_soft_reset(struct mantis_pci *mantis);
+
+extern int mantis_dvb_init(struct mantis_pci *mantis);
+extern int mantis_dvb_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_DVB_H */
diff --git a/drivers/media/dvb/mantis/mantis_evm.c b/drivers/media/dvb/mantis/mantis_evm.c
new file mode 100644
index 00000000000..a7b369a439d
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_evm.c
@@ -0,0 +1,117 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/kernel.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_link.h"
+#include "mantis_hif.h"
+#include "mantis_reg.h"
+
+static void mantis_hifevm_work(struct work_struct *work)
+{
+ struct mantis_ca *ca = container_of(work, struct mantis_ca, hif_evm_work);
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ u32 gpif_stat, gpif_mask;
+
+ gpif_stat = mmread(MANTIS_GPIF_STATUS);
+ gpif_mask = mmread(MANTIS_GPIF_IRQCFG);
+
+ if (gpif_stat & MANTIS_GPIF_DETSTAT) {
+ if (gpif_stat & MANTIS_CARD_PLUGIN) {
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Plugin", mantis->num);
+ mmwrite(0xdada0000, MANTIS_CARD_RESET);
+ mantis_event_cam_plugin(ca);
+ dvb_ca_en50221_camchange_irq(&ca->en50221,
+ 0,
+ DVB_CA_EN50221_CAMCHANGE_INSERTED);
+ }
+ } else {
+ if (gpif_stat & MANTIS_CARD_PLUGOUT) {
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Unplug", mantis->num);
+ mmwrite(0xdada0000, MANTIS_CARD_RESET);
+ mantis_event_cam_unplug(ca);
+ dvb_ca_en50221_camchange_irq(&ca->en50221,
+ 0,
+ DVB_CA_EN50221_CAMCHANGE_REMOVED);
+ }
+ }
+
+ if (mantis->gpif_status & MANTIS_GPIF_EXTIRQ)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Ext IRQ", mantis->num);
+
+ if (mantis->gpif_status & MANTIS_SBUF_WSTO)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Timeout", mantis->num);
+
+ if (mantis->gpif_status & MANTIS_GPIF_OTHERR)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Alignment Error", mantis->num);
+
+ if (gpif_stat & MANTIS_SBUF_OVFLW)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Overflow", mantis->num);
+
+ if (gpif_stat & MANTIS_GPIF_BRRDY)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Read Ready", mantis->num);
+
+ if (gpif_stat & MANTIS_GPIF_INTSTAT)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): GPIF IRQ", mantis->num);
+
+ if (gpif_stat & MANTIS_SBUF_EMPTY)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Empty", mantis->num);
+
+ if (gpif_stat & MANTIS_SBUF_OPDONE) {
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer operation complete", mantis->num);
+ ca->sbuf_status = MANTIS_SBUF_DATA_AVAIL;
+ ca->hif_event = MANTIS_SBUF_OPDONE;
+ wake_up(&ca->hif_opdone_wq);
+ }
+}
+
+int mantis_evmgr_init(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Initializing Mantis Host I/F Event manager");
+ INIT_WORK(&ca->hif_evm_work, mantis_hifevm_work);
+ mantis_pcmcia_init(ca);
+ schedule_work(&ca->hif_evm_work);
+ mantis_hif_init(ca);
+ return 0;
+}
+
+void mantis_evmgr_exit(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis Host I/F Event manager exiting");
+ flush_scheduled_work();
+ mantis_hif_exit(ca);
+ mantis_pcmcia_exit(ca);
+}
diff --git a/drivers/media/dvb/mantis/mantis_hif.c b/drivers/media/dvb/mantis/mantis_hif.c
new file mode 100644
index 00000000000..7477dac628b
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_hif.c
@@ -0,0 +1,240 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+
+#include "mantis_hif.h"
+#include "mantis_link.h" /* temporary due to physical layer stuff */
+
+#include "mantis_reg.h"
+
+
+static int mantis_hif_sbuf_opdone_wait(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+ int rc = 0;
+
+ if (wait_event_timeout(ca->hif_opdone_wq,
+ ca->hif_event & MANTIS_SBUF_OPDONE,
+ msecs_to_jiffies(500)) == -ERESTARTSYS) {
+
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Smart buffer operation timeout !", mantis->num);
+ rc = -EREMOTEIO;
+ }
+ dprintk(MANTIS_DEBUG, 1, "Smart Buffer Operation complete");
+ ca->hif_event &= ~MANTIS_SBUF_OPDONE;
+ return rc;
+}
+
+static int mantis_hif_write_wait(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 opdone = 0, timeout = 0;
+ int rc = 0;
+
+ if (wait_event_timeout(ca->hif_write_wq,
+ mantis->gpif_status & MANTIS_GPIF_WRACK,
+ msecs_to_jiffies(500)) == -ERESTARTSYS) {
+
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Write ACK timed out !", mantis->num);
+ rc = -EREMOTEIO;
+ }
+ dprintk(MANTIS_DEBUG, 1, "Write Acknowledged");
+ mantis->gpif_status &= ~MANTIS_GPIF_WRACK;
+ while (!opdone) {
+ opdone = (mmread(MANTIS_GPIF_STATUS) & MANTIS_SBUF_OPDONE);
+ udelay(500);
+ timeout++;
+ if (timeout > 100) {
+ dprintk(MANTIS_ERROR, 1, "Adater(%d) Slot(0): Write operation timed out!", mantis->num);
+ rc = -ETIMEDOUT;
+ break;
+ }
+ }
+ dprintk(MANTIS_DEBUG, 1, "HIF Write success");
+ return rc;
+}
+
+
+int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 hif_addr = 0, data, count = 4;
+
+ dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Read", mantis->num);
+ mutex_lock(&ca->ca_lock);
+ hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
+ hif_addr &= ~MANTIS_GPIF_PCMCIAIOM;
+ hif_addr |= MANTIS_HIF_STATUS;
+ hif_addr |= addr;
+
+ mmwrite(hif_addr, MANTIS_GPIF_BRADDR);
+ mmwrite(count, MANTIS_GPIF_BRBYTES);
+ udelay(20);
+ mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR);
+
+ if (mantis_hif_sbuf_opdone_wait(ca) != 0) {
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): GPIF Smart Buffer operation failed", mantis->num);
+ mutex_unlock(&ca->ca_lock);
+ return -EREMOTEIO;
+ }
+ data = mmread(MANTIS_GPIF_DIN);
+ mutex_unlock(&ca->ca_lock);
+ dprintk(MANTIS_DEBUG, 1, "Mem Read: 0x%02x", data);
+ return (data >> 24) & 0xff;
+}
+
+int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data)
+{
+ struct mantis_slot *slot = ca->slot;
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 hif_addr = 0;
+
+ dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Write", mantis->num);
+ mutex_lock(&ca->ca_lock);
+ hif_addr &= ~MANTIS_GPIF_HIFRDWRN;
+ hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
+ hif_addr &= ~MANTIS_GPIF_PCMCIAIOM;
+ hif_addr |= MANTIS_HIF_STATUS;
+ hif_addr |= addr;
+
+ mmwrite(slot->slave_cfg, MANTIS_GPIF_CFGSLA); /* Slot0 alone for now */
+ mmwrite(hif_addr, MANTIS_GPIF_ADDR);
+ mmwrite(data, MANTIS_GPIF_DOUT);
+
+ if (mantis_hif_write_wait(ca) != 0) {
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num);
+ mutex_unlock(&ca->ca_lock);
+ return -EREMOTEIO;
+ }
+ dprintk(MANTIS_DEBUG, 1, "Mem Write: (0x%02x to 0x%02x)", data, addr);
+ mutex_unlock(&ca->ca_lock);
+
+ return 0;
+}
+
+int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 data, hif_addr = 0;
+
+ dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Read", mantis->num);
+ mutex_lock(&ca->ca_lock);
+ hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
+ hif_addr |= MANTIS_GPIF_PCMCIAIOM;
+ hif_addr |= MANTIS_HIF_STATUS;
+ hif_addr |= addr;
+
+ mmwrite(hif_addr, MANTIS_GPIF_BRADDR);
+ mmwrite(1, MANTIS_GPIF_BRBYTES);
+ udelay(20);
+ mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR);
+
+ if (mantis_hif_sbuf_opdone_wait(ca) != 0) {
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num);
+ mutex_unlock(&ca->ca_lock);
+ return -EREMOTEIO;
+ }
+ data = mmread(MANTIS_GPIF_DIN);
+ dprintk(MANTIS_DEBUG, 1, "I/O Read: 0x%02x", data);
+ udelay(50);
+ mutex_unlock(&ca->ca_lock);
+
+ return (u8) data;
+}
+
+int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 hif_addr = 0;
+
+ dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Write", mantis->num);
+ mutex_lock(&ca->ca_lock);
+ hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
+ hif_addr &= ~MANTIS_GPIF_HIFRDWRN;
+ hif_addr |= MANTIS_GPIF_PCMCIAIOM;
+ hif_addr |= MANTIS_HIF_STATUS;
+ hif_addr |= addr;
+
+ mmwrite(hif_addr, MANTIS_GPIF_ADDR);
+ mmwrite(data, MANTIS_GPIF_DOUT);
+
+ if (mantis_hif_write_wait(ca) != 0) {
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num);
+ mutex_unlock(&ca->ca_lock);
+ return -EREMOTEIO;
+ }
+ dprintk(MANTIS_DEBUG, 1, "I/O Write: (0x%02x to 0x%02x)", data, addr);
+ mutex_unlock(&ca->ca_lock);
+ udelay(50);
+
+ return 0;
+}
+
+int mantis_hif_init(struct mantis_ca *ca)
+{
+ struct mantis_slot *slot = ca->slot;
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 irqcfg;
+
+ slot[0].slave_cfg = 0x70773028;
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Initializing Mantis Host Interface", mantis->num);
+
+ mutex_lock(&ca->ca_lock);
+ irqcfg = mmread(MANTIS_GPIF_IRQCFG);
+ irqcfg = MANTIS_MASK_BRRDY |
+ MANTIS_MASK_WRACK |
+ MANTIS_MASK_EXTIRQ |
+ MANTIS_MASK_WSTO |
+ MANTIS_MASK_OTHERR |
+ MANTIS_MASK_OVFLW;
+
+ mmwrite(irqcfg, MANTIS_GPIF_IRQCFG);
+ mutex_unlock(&ca->ca_lock);
+
+ return 0;
+}
+
+void mantis_hif_exit(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 irqcfg;
+
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Exiting Mantis Host Interface", mantis->num);
+ mutex_lock(&ca->ca_lock);
+ irqcfg = mmread(MANTIS_GPIF_IRQCFG);
+ irqcfg &= ~MANTIS_MASK_BRRDY;
+ mmwrite(irqcfg, MANTIS_GPIF_IRQCFG);
+ mutex_unlock(&ca->ca_lock);
+}
diff --git a/drivers/media/dvb/mantis/mantis_hif.h b/drivers/media/dvb/mantis/mantis_hif.h
new file mode 100644
index 00000000000..9094f9ed236
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_hif.h
@@ -0,0 +1,29 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MANTIS_HIF_H
+#define __MANTIS_HIF_H
+
+#define MANTIS_HIF_MEMRD 1
+#define MANTIS_HIF_MEMWR 2
+#define MANTIS_HIF_IOMRD 3
+#define MANTIS_HIF_IOMWR 4
+
+#endif /* __MANTIS_HIF_H */
diff --git a/drivers/media/dvb/mantis/mantis_i2c.c b/drivers/media/dvb/mantis/mantis_i2c.c
new file mode 100644
index 00000000000..7870bcf9689
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_i2c.c
@@ -0,0 +1,267 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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 <asm/io.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_i2c.h"
+
+#define TRIALS 10000
+
+static int mantis_i2c_read(struct mantis_pci *mantis, const struct i2c_msg *msg)
+{
+ u32 rxd, i, stat, trials;
+
+ dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] <R>[ ",
+ __func__, msg->addr);
+
+ for (i = 0; i < msg->len; i++) {
+ rxd = (msg->addr << 25) | (1 << 24)
+ | MANTIS_I2C_RATE_3
+ | MANTIS_I2C_STOP
+ | MANTIS_I2C_PGMODE;
+
+ if (i == (msg->len - 1))
+ rxd &= ~MANTIS_I2C_STOP;
+
+ mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
+ mmwrite(rxd, MANTIS_I2CDATA_CTL);
+
+ /* wait for xfer completion */
+ for (trials = 0; trials < TRIALS; trials++) {
+ stat = mmread(MANTIS_INT_STAT);
+ if (stat & MANTIS_INT_I2CDONE)
+ break;
+ }
+
+ dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials);
+
+ /* wait for xfer completion */
+ for (trials = 0; trials < TRIALS; trials++) {
+ stat = mmread(MANTIS_INT_STAT);
+ if (stat & MANTIS_INT_I2CRACK)
+ break;
+ }
+
+ dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials);
+
+ rxd = mmread(MANTIS_I2CDATA_CTL);
+ msg->buf[i] = (u8)((rxd >> 8) & 0xFF);
+ dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]);
+ }
+ dprintk(MANTIS_INFO, 0, "]\n");
+
+ return 0;
+}
+
+static int mantis_i2c_write(struct mantis_pci *mantis, const struct i2c_msg *msg)
+{
+ int i;
+ u32 txd = 0, stat, trials;
+
+ dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] <W>[ ",
+ __func__, msg->addr);
+
+ for (i = 0; i < msg->len; i++) {
+ dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]);
+ txd = (msg->addr << 25) | (msg->buf[i] << 8)
+ | MANTIS_I2C_RATE_3
+ | MANTIS_I2C_STOP
+ | MANTIS_I2C_PGMODE;
+
+ if (i == (msg->len - 1))
+ txd &= ~MANTIS_I2C_STOP;
+
+ mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
+ mmwrite(txd, MANTIS_I2CDATA_CTL);
+
+ /* wait for xfer completion */
+ for (trials = 0; trials < TRIALS; trials++) {
+ stat = mmread(MANTIS_INT_STAT);
+ if (stat & MANTIS_INT_I2CDONE)
+ break;
+ }
+
+ dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials);
+
+ /* wait for xfer completion */
+ for (trials = 0; trials < TRIALS; trials++) {
+ stat = mmread(MANTIS_INT_STAT);
+ if (stat & MANTIS_INT_I2CRACK)
+ break;
+ }
+
+ dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials);
+ }
+ dprintk(MANTIS_INFO, 0, "]\n");
+
+ return 0;
+}
+
+static int mantis_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
+{
+ int ret = 0, i = 0, trials;
+ u32 stat, data, txd;
+ struct mantis_pci *mantis;
+ struct mantis_hwconfig *config;
+
+ mantis = i2c_get_adapdata(adapter);
+ BUG_ON(!mantis);
+ config = mantis->hwconfig;
+ BUG_ON(!config);
+
+ dprintk(MANTIS_DEBUG, 1, "Messages:%d", num);
+ mutex_lock(&mantis->i2c_lock);
+
+ while (i < num) {
+ /* Byte MODE */
+ if ((config->i2c_mode & MANTIS_BYTE_MODE) &&
+ ((i + 1) < num) &&
+ (msgs[i].len < 2) &&
+ (msgs[i + 1].len < 2) &&
+ (msgs[i + 1].flags & I2C_M_RD)) {
+
+ dprintk(MANTIS_DEBUG, 0, " Byte MODE:\n");
+
+ /* Read operation */
+ txd = msgs[i].addr << 25 | (0x1 << 24)
+ | (msgs[i].buf[0] << 16)
+ | MANTIS_I2C_RATE_3;
+
+ mmwrite(txd, MANTIS_I2CDATA_CTL);
+ /* wait for xfer completion */
+ for (trials = 0; trials < TRIALS; trials++) {
+ stat = mmread(MANTIS_INT_STAT);
+ if (stat & MANTIS_INT_I2CDONE)
+ break;
+ }
+
+ /* check for xfer completion */
+ if (stat & MANTIS_INT_I2CDONE) {
+ /* check xfer was acknowledged */
+ if (stat & MANTIS_INT_I2CRACK) {
+ data = mmread(MANTIS_I2CDATA_CTL);
+ msgs[i + 1].buf[0] = (data >> 8) & 0xff;
+ dprintk(MANTIS_DEBUG, 0, " Byte <%d> RXD=0x%02x [%02x]\n", 0x0, data, msgs[i + 1].buf[0]);
+ } else {
+ /* I/O error */
+ dprintk(MANTIS_ERROR, 1, " I/O error, LINE:%d", __LINE__);
+ ret = -EIO;
+ break;
+ }
+ } else {
+ /* I/O error */
+ dprintk(MANTIS_ERROR, 1, " I/O error, LINE:%d", __LINE__);
+ ret = -EIO;
+ break;
+ }
+ i += 2; /* Write/Read operation in one go */
+ }
+
+ if (i < num) {
+ if (msgs[i].flags & I2C_M_RD)
+ ret = mantis_i2c_read(mantis, &msgs[i]);
+ else
+ ret = mantis_i2c_write(mantis, &msgs[i]);
+
+ i++;
+ if (ret < 0)
+ goto bail_out;
+ }
+
+ }
+
+ mutex_unlock(&mantis->i2c_lock);
+
+ return num;
+
+bail_out:
+ mutex_unlock(&mantis->i2c_lock);
+ return ret;
+}
+
+static u32 mantis_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm mantis_algo = {
+ .master_xfer = mantis_i2c_xfer,
+ .functionality = mantis_i2c_func,
+};
+
+int __devinit mantis_i2c_init(struct mantis_pci *mantis)
+{
+ u32 intstat, intmask;
+ struct i2c_adapter *i2c_adapter = &mantis->adapter;
+ struct pci_dev *pdev = mantis->pdev;
+
+ init_waitqueue_head(&mantis->i2c_wq);
+ mutex_init(&mantis->i2c_lock);
+ strncpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name));
+ i2c_set_adapdata(i2c_adapter, mantis);
+
+ i2c_adapter->owner = THIS_MODULE;
+ i2c_adapter->class = I2C_CLASS_TV_DIGITAL;
+ i2c_adapter->algo = &mantis_algo;
+ i2c_adapter->algo_data = NULL;
+ i2c_adapter->timeout = 500;
+ i2c_adapter->retries = 3;
+ i2c_adapter->dev.parent = &pdev->dev;
+
+ mantis->i2c_rc = i2c_add_adapter(i2c_adapter);
+ if (mantis->i2c_rc < 0)
+ return mantis->i2c_rc;
+
+ dprintk(MANTIS_DEBUG, 1, "Initializing I2C ..");
+
+ intstat = mmread(MANTIS_INT_STAT);
+ intmask = mmread(MANTIS_INT_MASK);
+ mmwrite(intstat, MANTIS_INT_STAT);
+ dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
+ intmask = mmread(MANTIS_INT_MASK);
+ mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_i2c_init);
+
+int mantis_i2c_exit(struct mantis_pci *mantis)
+{
+ u32 intmask;
+
+ dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
+ intmask = mmread(MANTIS_INT_MASK);
+ mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK);
+
+ dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter");
+ return i2c_del_adapter(&mantis->adapter);
+}
+EXPORT_SYMBOL_GPL(mantis_i2c_exit);
diff --git a/drivers/media/dvb/mantis/mantis_i2c.h b/drivers/media/dvb/mantis/mantis_i2c.h
new file mode 100644
index 00000000000..1342df2faed
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_i2c.h
@@ -0,0 +1,30 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MANTIS_I2C_H
+#define __MANTIS_I2C_H
+
+#define I2C_STOP (1 << 0)
+#define I2C_READ (1 << 1)
+
+extern int mantis_i2c_init(struct mantis_pci *mantis);
+extern int mantis_i2c_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_I2C_H */
diff --git a/drivers/media/dvb/mantis/mantis_input.c b/drivers/media/dvb/mantis/mantis_input.c
new file mode 100644
index 00000000000..6a9df779441
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_input.c
@@ -0,0 +1,148 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/input.h>
+#include <media/ir-common.h>
+#include <linux/pci.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_uart.h"
+
+static struct ir_scancode mantis_ir_table[] = {
+ { 0x29, KEY_POWER },
+ { 0x28, KEY_FAVORITES },
+ { 0x30, KEY_TEXT },
+ { 0x17, KEY_INFO }, /* Preview */
+ { 0x23, KEY_EPG },
+ { 0x3b, KEY_F22 }, /* Record List */
+ { 0x3c, KEY_1 },
+ { 0x3e, KEY_2 },
+ { 0x39, KEY_3 },
+ { 0x36, KEY_4 },
+ { 0x22, KEY_5 },
+ { 0x20, KEY_6 },
+ { 0x32, KEY_7 },
+ { 0x26, KEY_8 },
+ { 0x24, KEY_9 },
+ { 0x2a, KEY_0 },
+
+ { 0x33, KEY_CANCEL },
+ { 0x2c, KEY_BACK },
+ { 0x15, KEY_CLEAR },
+ { 0x3f, KEY_TAB },
+ { 0x10, KEY_ENTER },
+ { 0x14, KEY_UP },
+ { 0x0d, KEY_RIGHT },
+ { 0x0e, KEY_DOWN },
+ { 0x11, KEY_LEFT },
+
+ { 0x21, KEY_VOLUMEUP },
+ { 0x35, KEY_VOLUMEDOWN },
+ { 0x3d, KEY_CHANNELDOWN },
+ { 0x3a, KEY_CHANNELUP },
+ { 0x2e, KEY_RECORD },
+ { 0x2b, KEY_PLAY },
+ { 0x13, KEY_PAUSE },
+ { 0x25, KEY_STOP },
+
+ { 0x1f, KEY_REWIND },
+ { 0x2d, KEY_FASTFORWARD },
+ { 0x1e, KEY_PREVIOUS }, /* Replay |< */
+ { 0x1d, KEY_NEXT }, /* Skip >| */
+
+ { 0x0b, KEY_CAMERA }, /* Capture */
+ { 0x0f, KEY_LANGUAGE }, /* SAP */
+ { 0x18, KEY_MODE }, /* PIP */
+ { 0x12, KEY_ZOOM }, /* Full screen */
+ { 0x1c, KEY_SUBTITLE },
+ { 0x2f, KEY_MUTE },
+ { 0x16, KEY_F20 }, /* L/R */
+ { 0x38, KEY_F21 }, /* Hibernate */
+
+ { 0x37, KEY_SWITCHVIDEOMODE }, /* A/V */
+ { 0x31, KEY_AGAIN }, /* Recall */
+ { 0x1a, KEY_KPPLUS }, /* Zoom+ */
+ { 0x19, KEY_KPMINUS }, /* Zoom- */
+ { 0x27, KEY_RED },
+ { 0x0C, KEY_GREEN },
+ { 0x01, KEY_YELLOW },
+ { 0x00, KEY_BLUE },
+};
+
+struct ir_scancode_table ir_mantis = {
+ .scan = mantis_ir_table,
+ .size = ARRAY_SIZE(mantis_ir_table),
+};
+EXPORT_SYMBOL_GPL(ir_mantis);
+
+int mantis_input_init(struct mantis_pci *mantis)
+{
+ struct input_dev *rc;
+ struct ir_input_state rc_state;
+ char name[80], dev[80];
+ int err;
+
+ rc = input_allocate_device();
+ if (!rc) {
+ dprintk(MANTIS_ERROR, 1, "Input device allocate failed");
+ return -ENOMEM;
+ }
+
+ sprintf(name, "Mantis %s IR receiver", mantis->hwconfig->model_name);
+ sprintf(dev, "pci-%s/ir0", pci_name(mantis->pdev));
+
+ rc->name = name;
+ rc->phys = dev;
+
+ ir_input_init(rc, &rc_state, IR_TYPE_OTHER);
+
+ rc->id.bustype = BUS_PCI;
+ rc->id.vendor = mantis->vendor_id;
+ rc->id.product = mantis->device_id;
+ rc->id.version = 1;
+ rc->dev = mantis->pdev->dev;
+
+ err = ir_input_register(rc, &ir_mantis);
+ if (err) {
+ dprintk(MANTIS_ERROR, 1, "IR device registration failed, ret = %d", err);
+ input_free_device(rc);
+ return -ENODEV;
+ }
+
+ mantis->rc = rc;
+
+ return 0;
+}
+
+int mantis_exit(struct mantis_pci *mantis)
+{
+ struct input_dev *rc = mantis->rc;
+
+ ir_input_unregister(rc);
+
+ return 0;
+}
diff --git a/drivers/media/dvb/mantis/mantis_ioc.c b/drivers/media/dvb/mantis/mantis_ioc.c
new file mode 100644
index 00000000000..de148ded52d
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_ioc.c
@@ -0,0 +1,130 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/kernel.h>
+#include <linux/i2c.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_ioc.h"
+
+static int read_eeprom_bytes(struct mantis_pci *mantis, u8 reg, u8 *data, u8 length)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+ int err;
+ u8 buf = reg;
+
+ struct i2c_msg msg[] = {
+ { .addr = 0x50, .flags = 0, .buf = &buf, .len = 1 },
+ { .addr = 0x50, .flags = I2C_M_RD, .buf = data, .len = length },
+ };
+
+ err = i2c_transfer(adapter, msg, 2);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >",
+ err, data[0], data[1]);
+
+ return err;
+ }
+
+ return 0;
+}
+int mantis_get_mac(struct mantis_pci *mantis)
+{
+ int err;
+ u8 mac_addr[6] = {0};
+
+ err = read_eeprom_bytes(mantis, 0x08, mac_addr, 6);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis EEPROM read error <%d>", err);
+
+ return err;
+ }
+
+ dprintk(MANTIS_ERROR, 0,
+ " MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]\n",
+ mac_addr[0],
+ mac_addr[1],
+ mac_addr[2],
+ mac_addr[3],
+ mac_addr[4],
+ mac_addr[5]);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_get_mac);
+
+/* Turn the given bit on or off. */
+void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
+{
+ u32 cur;
+
+ dprintk(MANTIS_DEBUG, 1, "Set Bit <%d> to <%d>", bitpos, value);
+ cur = mmread(MANTIS_GPIF_ADDR);
+ if (value)
+ mantis->gpio_status = cur | (1 << bitpos);
+ else
+ mantis->gpio_status = cur & (~(1 << bitpos));
+
+ dprintk(MANTIS_DEBUG, 1, "GPIO Value <%02x>", mantis->gpio_status);
+ mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR);
+ mmwrite(0x00, MANTIS_GPIF_DOUT);
+}
+EXPORT_SYMBOL_GPL(gpio_set_bits);
+
+int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl)
+{
+ u32 reg;
+
+ reg = mmread(MANTIS_CONTROL);
+ switch (stream_ctl) {
+ case STREAM_TO_HIF:
+ dprintk(MANTIS_DEBUG, 1, "Set stream to HIF");
+ reg &= 0xff - MANTIS_BYPASS;
+ mmwrite(reg, MANTIS_CONTROL);
+ reg |= MANTIS_BYPASS;
+ mmwrite(reg, MANTIS_CONTROL);
+ break;
+
+ case STREAM_TO_CAM:
+ dprintk(MANTIS_DEBUG, 1, "Set stream to CAM");
+ reg |= MANTIS_BYPASS;
+ mmwrite(reg, MANTIS_CONTROL);
+ reg &= 0xff - MANTIS_BYPASS;
+ mmwrite(reg, MANTIS_CONTROL);
+ break;
+ default:
+ dprintk(MANTIS_ERROR, 1, "Unknown MODE <%02x>", stream_ctl);
+ return -1;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_stream_control);
diff --git a/drivers/media/dvb/mantis/mantis_ioc.h b/drivers/media/dvb/mantis/mantis_ioc.h
new file mode 100644
index 00000000000..188fe5a8161
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_ioc.h
@@ -0,0 +1,51 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MANTIS_IOC_H
+#define __MANTIS_IOC_H
+
+#define GPIF_A00 0x00
+#define GPIF_A01 0x01
+#define GPIF_A02 0x02
+#define GPIF_A03 0x03
+#define GPIF_A04 0x04
+#define GPIF_A05 0x05
+#define GPIF_A06 0x06
+#define GPIF_A07 0x07
+#define GPIF_A08 0x08
+#define GPIF_A09 0x09
+#define GPIF_A10 0x0a
+#define GPIF_A11 0x0b
+
+#define GPIF_A12 0x0c
+#define GPIF_A13 0x0d
+#define GPIF_A14 0x0e
+
+enum mantis_stream_control {
+ STREAM_TO_HIF = 0,
+ STREAM_TO_CAM
+};
+
+extern int mantis_get_mac(struct mantis_pci *mantis);
+extern void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value);
+
+extern int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl);
+
+#endif /* __MANTIS_IOC_H */
diff --git a/drivers/media/dvb/mantis/mantis_link.h b/drivers/media/dvb/mantis/mantis_link.h
new file mode 100644
index 00000000000..2a814774a00
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_link.h
@@ -0,0 +1,83 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MANTIS_LINK_H
+#define __MANTIS_LINK_H
+
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include "dvb_ca_en50221.h"
+
+enum mantis_sbuf_status {
+ MANTIS_SBUF_DATA_AVAIL = 1,
+ MANTIS_SBUF_DATA_EMPTY = 2,
+ MANTIS_SBUF_DATA_OVFLW = 3
+};
+
+struct mantis_slot {
+ u32 timeout;
+ u32 slave_cfg;
+ u32 bar;
+};
+
+/* Physical layer */
+enum mantis_slot_state {
+ MODULE_INSERTED = 3,
+ MODULE_XTRACTED = 4
+};
+
+struct mantis_ca {
+ struct mantis_slot slot[4];
+
+ struct work_struct hif_evm_work;
+
+ u32 hif_event;
+ wait_queue_head_t hif_opdone_wq;
+ wait_queue_head_t hif_brrdyw_wq;
+ wait_queue_head_t hif_data_wq;
+ wait_queue_head_t hif_write_wq; /* HIF Write op */
+
+ enum mantis_sbuf_status sbuf_status;
+
+ enum mantis_slot_state slot_state;
+
+ void *ca_priv;
+
+ struct dvb_ca_en50221 en50221;
+ struct mutex ca_lock;
+};
+
+/* CA */
+extern void mantis_event_cam_plugin(struct mantis_ca *ca);
+extern void mantis_event_cam_unplug(struct mantis_ca *ca);
+extern int mantis_pcmcia_init(struct mantis_ca *ca);
+extern void mantis_pcmcia_exit(struct mantis_ca *ca);
+extern int mantis_evmgr_init(struct mantis_ca *ca);
+extern void mantis_evmgr_exit(struct mantis_ca *ca);
+
+/* HIF */
+extern int mantis_hif_init(struct mantis_ca *ca);
+extern void mantis_hif_exit(struct mantis_ca *ca);
+extern int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr);
+extern int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data);
+extern int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr);
+extern int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data);
+
+#endif /* __MANTIS_LINK_H */
diff --git a/drivers/media/dvb/mantis/mantis_pci.c b/drivers/media/dvb/mantis/mantis_pci.c
new file mode 100644
index 00000000000..6c7534af6b4
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_pci.c
@@ -0,0 +1,177 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/moduleparam.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/kmod.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+
+#include <asm/irq.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include <asm/irq.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_pci.h"
+
+#define DRIVER_NAME "Mantis Core"
+
+int __devinit mantis_pci_init(struct mantis_pci *mantis)
+{
+ u8 revision, latency;
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ struct pci_dev *pdev = mantis->pdev;
+ int err, ret = 0;
+
+ dprintk(MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n",
+ config->model_name,
+ config->dev_type,
+ mantis->pdev->bus->number,
+ PCI_SLOT(mantis->pdev->devfn),
+ PCI_FUNC(mantis->pdev->devfn));
+
+ err = pci_enable_device(pdev);
+ if (err != 0) {
+ ret = -ENODEV;
+ dprintk(MANTIS_ERROR, 1, "ERROR: PCI enable failed <%i>", err);
+ goto fail0;
+ }
+
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (err != 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Unable to obtain 32 bit DMA <%i>", err);
+ ret = -ENOMEM;
+ goto fail1;
+ }
+
+ pci_set_master(pdev);
+
+ if (!request_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0),
+ DRIVER_NAME)) {
+
+ dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 Request failed !");
+ ret = -ENODEV;
+ goto fail1;
+ }
+
+ mantis->mmio = ioremap(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+
+ if (!mantis->mmio) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 remap failed !");
+ ret = -ENODEV;
+ goto fail2;
+ }
+
+ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
+ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+ mantis->latency = latency;
+ mantis->revision = revision;
+
+ dprintk(MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ",
+ mantis->revision,
+ mantis->pdev->subsystem_vendor,
+ mantis->pdev->subsystem_device);
+
+ dprintk(MANTIS_ERROR, 0,
+ "irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n",
+ mantis->pdev->irq,
+ mantis->latency,
+ mantis->mantis_addr,
+ mantis->mmio);
+
+ err = request_irq(pdev->irq,
+ config->irq_handler,
+ IRQF_SHARED,
+ DRIVER_NAME,
+ mantis);
+
+ if (err != 0) {
+
+ dprintk(MANTIS_ERROR, 1, "ERROR: IRQ registration failed ! <%d>", err);
+ ret = -ENODEV;
+ goto fail3;
+ }
+
+ pci_set_drvdata(pdev, mantis);
+ return ret;
+
+ /* Error conditions */
+fail3:
+ dprintk(MANTIS_ERROR, 1, "ERROR: <%d> I/O unmap", ret);
+ if (mantis->mmio)
+ iounmap(mantis->mmio);
+
+fail2:
+ dprintk(MANTIS_ERROR, 1, "ERROR: <%d> releasing regions", ret);
+ release_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+
+fail1:
+ dprintk(MANTIS_ERROR, 1, "ERROR: <%d> disabling device", ret);
+ pci_disable_device(pdev);
+
+fail0:
+ dprintk(MANTIS_ERROR, 1, "ERROR: <%d> exiting", ret);
+ pci_set_drvdata(pdev, NULL);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mantis_pci_init);
+
+void mantis_pci_exit(struct mantis_pci *mantis)
+{
+ struct pci_dev *pdev = mantis->pdev;
+
+ dprintk(MANTIS_NOTICE, 1, " mem: 0x%p", mantis->mmio);
+ free_irq(pdev->irq, mantis);
+ if (mantis->mmio) {
+ iounmap(mantis->mmio);
+ release_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ }
+
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+}
+EXPORT_SYMBOL_GPL(mantis_pci_exit);
+
+MODULE_DESCRIPTION("Mantis PCI DTV bridge driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/mantis/mantis_pci.h b/drivers/media/dvb/mantis/mantis_pci.h
new file mode 100644
index 00000000000..65f00451908
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_pci.h
@@ -0,0 +1,27 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MANTIS_PCI_H
+#define __MANTIS_PCI_H
+
+extern int mantis_pci_init(struct mantis_pci *mantis);
+extern void mantis_pci_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_PCI_H */
diff --git a/drivers/media/dvb/mantis/mantis_pcmcia.c b/drivers/media/dvb/mantis/mantis_pcmcia.c
new file mode 100644
index 00000000000..5cb545b913f
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_pcmcia.c
@@ -0,0 +1,120 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/kernel.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_link.h" /* temporary due to physical layer stuff */
+#include "mantis_reg.h"
+
+/*
+ * If Slot state is already PLUG_IN event and we are called
+ * again, definitely it is jitter alone
+ */
+void mantis_event_cam_plugin(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ u32 gpif_irqcfg;
+
+ if (ca->slot_state == MODULE_XTRACTED) {
+ dprintk(MANTIS_DEBUG, 1, "Event: CAM Plugged IN: Adapter(%d) Slot(0)", mantis->num);
+ udelay(50);
+ mmwrite(0xda000000, MANTIS_CARD_RESET);
+ gpif_irqcfg = mmread(MANTIS_GPIF_IRQCFG);
+ gpif_irqcfg |= MANTIS_MASK_PLUGOUT;
+ gpif_irqcfg &= ~MANTIS_MASK_PLUGIN;
+ mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG);
+ udelay(500);
+ ca->slot_state = MODULE_INSERTED;
+ }
+ udelay(100);
+}
+
+/*
+ * If Slot state is already UN_PLUG event and we are called
+ * again, definitely it is jitter alone
+ */
+void mantis_event_cam_unplug(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ u32 gpif_irqcfg;
+
+ if (ca->slot_state == MODULE_INSERTED) {
+ dprintk(MANTIS_DEBUG, 1, "Event: CAM Unplugged: Adapter(%d) Slot(0)", mantis->num);
+ udelay(50);
+ mmwrite(0x00da0000, MANTIS_CARD_RESET);
+ gpif_irqcfg = mmread(MANTIS_GPIF_IRQCFG);
+ gpif_irqcfg |= MANTIS_MASK_PLUGIN;
+ gpif_irqcfg &= ~MANTIS_MASK_PLUGOUT;
+ mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG);
+ udelay(500);
+ ca->slot_state = MODULE_XTRACTED;
+ }
+ udelay(100);
+}
+
+int mantis_pcmcia_init(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ u32 gpif_stat, card_stat;
+
+ mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_IRQ0, MANTIS_INT_MASK);
+ gpif_stat = mmread(MANTIS_GPIF_STATUS);
+ card_stat = mmread(MANTIS_GPIF_IRQCFG);
+
+ if (gpif_stat & MANTIS_GPIF_DETSTAT) {
+ dprintk(MANTIS_DEBUG, 1, "CAM found on Adapter(%d) Slot(0)", mantis->num);
+ mmwrite(card_stat | MANTIS_MASK_PLUGOUT, MANTIS_GPIF_IRQCFG);
+ ca->slot_state = MODULE_INSERTED;
+ dvb_ca_en50221_camchange_irq(&ca->en50221,
+ 0,
+ DVB_CA_EN50221_CAMCHANGE_INSERTED);
+ } else {
+ dprintk(MANTIS_DEBUG, 1, "Empty Slot on Adapter(%d) Slot(0)", mantis->num);
+ mmwrite(card_stat | MANTIS_MASK_PLUGIN, MANTIS_GPIF_IRQCFG);
+ ca->slot_state = MODULE_XTRACTED;
+ dvb_ca_en50221_camchange_irq(&ca->en50221,
+ 0,
+ DVB_CA_EN50221_CAMCHANGE_REMOVED);
+ }
+
+ return 0;
+}
+
+void mantis_pcmcia_exit(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ mmwrite(mmread(MANTIS_GPIF_STATUS) & (~MANTIS_CARD_PLUGOUT | ~MANTIS_CARD_PLUGIN), MANTIS_GPIF_STATUS);
+ mmwrite(mmread(MANTIS_INT_MASK) & ~MANTIS_INT_IRQ0, MANTIS_INT_MASK);
+}
diff --git a/drivers/media/dvb/mantis/mantis_reg.h b/drivers/media/dvb/mantis/mantis_reg.h
new file mode 100644
index 00000000000..7761f9dc7fe
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_reg.h
@@ -0,0 +1,197 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MANTIS_REG_H
+#define __MANTIS_REG_H
+
+/* Interrupts */
+#define MANTIS_INT_STAT 0x00
+#define MANTIS_INT_MASK 0x04
+
+#define MANTIS_INT_RISCSTAT (0x0f << 28)
+#define MANTIS_INT_RISCEN (0x01 << 27)
+#define MANTIS_INT_I2CRACK (0x01 << 26)
+
+/* #define MANTIS_INT_GPIF (0xff << 12) */
+
+#define MANTIS_INT_PCMCIA7 (0x01 << 19)
+#define MANTIS_INT_PCMCIA6 (0x01 << 18)
+#define MANTIS_INT_PCMCIA5 (0x01 << 17)
+#define MANTIS_INT_PCMCIA4 (0x01 << 16)
+#define MANTIS_INT_PCMCIA3 (0x01 << 15)
+#define MANTIS_INT_PCMCIA2 (0x01 << 14)
+#define MANTIS_INT_PCMCIA1 (0x01 << 13)
+#define MANTIS_INT_PCMCIA0 (0x01 << 12)
+#define MANTIS_INT_IRQ1 (0x01 << 11)
+#define MANTIS_INT_IRQ0 (0x01 << 10)
+#define MANTIS_INT_OCERR (0x01 << 8)
+#define MANTIS_INT_PABORT (0x01 << 7)
+#define MANTIS_INT_RIPERR (0x01 << 6)
+#define MANTIS_INT_PPERR (0x01 << 5)
+#define MANTIS_INT_FTRGT (0x01 << 3)
+#define MANTIS_INT_RISCI (0x01 << 1)
+#define MANTIS_INT_I2CDONE (0x01 << 0)
+
+/* DMA */
+#define MANTIS_DMA_CTL 0x08
+#define MANTIS_GPIF_RD (0xff << 24)
+#define MANTIS_GPIF_WR (0xff << 16)
+#define MANTIS_CPU_DO (0x01 << 10)
+#define MANTIS_DRV_DO (0x01 << 9)
+#define MANTIS_I2C_RD (0x01 << 7)
+#define MANTIS_I2C_WR (0x01 << 6)
+#define MANTIS_DCAP_MODE (0x01 << 5)
+#define MANTIS_FIFO_TP_4 (0x00 << 3)
+#define MANTIS_FIFO_TP_8 (0x01 << 3)
+#define MANTIS_FIFO_TP_16 (0x02 << 3)
+#define MANTIS_FIFO_EN (0x01 << 2)
+#define MANTIS_DCAP_EN (0x01 << 1)
+#define MANTIS_RISC_EN (0x01 << 0)
+
+/* DEBUG */
+#define MANTIS_DEBUGREG 0x0c
+#define MANTIS_DATINV (0x0e << 7)
+#define MANTIS_TOP_DEBUGSEL (0x07 << 4)
+#define MANTIS_PCMCIA_DEBUGSEL (0x0f << 0)
+
+#define MANTIS_RISC_START 0x10
+#define MANTIS_RISC_PC 0x14
+
+/* I2C */
+#define MANTIS_I2CDATA_CTL 0x18
+#define MANTIS_I2C_RATE_1 (0x00 << 6)
+#define MANTIS_I2C_RATE_2 (0x01 << 6)
+#define MANTIS_I2C_RATE_3 (0x02 << 6)
+#define MANTIS_I2C_RATE_4 (0x03 << 6)
+#define MANTIS_I2C_STOP (0x01 << 5)
+#define MANTIS_I2C_PGMODE (0x01 << 3)
+
+/* DATA */
+#define MANTIS_CMD_DATA_R1 0x20
+#define MANTIS_CMD_DATA_3 (0xff << 24)
+#define MANTIS_CMD_DATA_2 (0xff << 16)
+#define MANTIS_CMD_DATA_1 (0xff << 8)
+#define MANTIS_CMD_DATA_0 (0xff << 0)
+
+#define MANTIS_CMD_DATA_R2 0x24
+#define MANTIS_CMD_DATA_7 (0xff << 24)
+#define MANTIS_CMD_DATA_6 (0xff << 16)
+#define MANTIS_CMD_DATA_5 (0xff << 8)
+#define MANTIS_CMD_DATA_4 (0xff << 0)
+
+#define MANTIS_CONTROL 0x28
+#define MANTIS_DET (0x01 << 7)
+#define MANTIS_DAT_CF_EN (0x01 << 6)
+#define MANTIS_ACS (0x03 << 4)
+#define MANTIS_VCCEN (0x01 << 3)
+#define MANTIS_BYPASS (0x01 << 2)
+#define MANTIS_MRST (0x01 << 1)
+#define MANTIS_CRST_INT (0x01 << 0)
+
+#define MANTIS_GPIF_CFGSLA 0x84
+#define MANTIS_GPIF_WAITSMPL (0x07 << 28)
+#define MANTIS_GPIF_BYTEADDRSUB (0x01 << 25)
+#define MANTIS_GPIF_WAITPOL (0x01 << 24)
+#define MANTIS_GPIF_NCDELAY (0x07 << 20)
+#define MANTIS_GPIF_RW2CSDELAY (0x07 << 16)
+#define MANTIS_GPIF_SLFTIMEDMODE (0x01 << 15)
+#define MANTIS_GPIF_SLFTIMEDDELY (0x7f << 8)
+#define MANTIS_GPIF_DEVTYPE (0x07 << 4)
+#define MANTIS_GPIF_BIGENDIAN (0x01 << 3)
+#define MANTIS_GPIF_FETCHCMD (0x03 << 1)
+#define MANTIS_GPIF_HWORDDEV (0x01 << 0)
+
+#define MANTIS_GPIF_WSTOPER 0x90
+#define MANTIS_GPIF_WSTOPERWREN3 (0x01 << 31)
+#define MANTIS_GPIF_PARBOOTN (0x01 << 29)
+#define MANTIS_GPIF_WSTOPERSLID3 (0x1f << 24)
+#define MANTIS_GPIF_WSTOPERWREN2 (0x01 << 23)
+#define MANTIS_GPIF_WSTOPERSLID2 (0x1f << 16)
+#define MANTIS_GPIF_WSTOPERWREN1 (0x01 << 15)
+#define MANTIS_GPIF_WSTOPERSLID1 (0x1f << 8)
+#define MANTIS_GPIF_WSTOPERWREN0 (0x01 << 7)
+#define MANTIS_GPIF_WSTOPERSLID0 (0x1f << 0)
+
+#define MANTIS_GPIF_CS2RW 0x94
+#define MANTIS_GPIF_CS2RWWREN3 (0x01 << 31)
+#define MANTIS_GPIF_CS2RWDELY3 (0x3f << 24)
+#define MANTIS_GPIF_CS2RWWREN2 (0x01 << 23)
+#define MANTIS_GPIF_CS2RWDELY2 (0x3f << 16)
+#define MANTIS_GPIF_CS2RWWREN1 (0x01 << 15)
+#define MANTIS_GPIF_CS2RWDELY1 (0x3f << 8)
+#define MANTIS_GPIF_CS2RWWREN0 (0x01 << 7)
+#define MANTIS_GPIF_CS2RWDELY0 (0x3f << 0)
+
+#define MANTIS_GPIF_IRQCFG 0x98
+#define MANTIS_GPIF_IRQPOL (0x01 << 8)
+#define MANTIS_MASK_WRACK (0x01 << 7)
+#define MANTIS_MASK_BRRDY (0x01 << 6)
+#define MANTIS_MASK_OVFLW (0x01 << 5)
+#define MANTIS_MASK_OTHERR (0x01 << 4)
+#define MANTIS_MASK_WSTO (0x01 << 3)
+#define MANTIS_MASK_EXTIRQ (0x01 << 2)
+#define MANTIS_MASK_PLUGIN (0x01 << 1)
+#define MANTIS_MASK_PLUGOUT (0x01 << 0)
+
+#define MANTIS_GPIF_STATUS 0x9c
+#define MANTIS_SBUF_KILLOP (0x01 << 15)
+#define MANTIS_SBUF_OPDONE (0x01 << 14)
+#define MANTIS_SBUF_EMPTY (0x01 << 13)
+#define MANTIS_GPIF_DETSTAT (0x01 << 9)
+#define MANTIS_GPIF_INTSTAT (0x01 << 8)
+#define MANTIS_GPIF_WRACK (0x01 << 7)
+#define MANTIS_GPIF_BRRDY (0x01 << 6)
+#define MANTIS_SBUF_OVFLW (0x01 << 5)
+#define MANTIS_GPIF_OTHERR (0x01 << 4)
+#define MANTIS_SBUF_WSTO (0x01 << 3)
+#define MANTIS_GPIF_EXTIRQ (0x01 << 2)
+#define MANTIS_CARD_PLUGIN (0x01 << 1)
+#define MANTIS_CARD_PLUGOUT (0x01 << 0)
+
+#define MANTIS_GPIF_BRADDR 0xa0
+#define MANTIS_GPIF_PCMCIAREG (0x01 << 27)
+#define MANTIS_GPIF_PCMCIAIOM (0x01 << 26)
+#define MANTIS_GPIF_BR_ADDR (0xfffffff << 0)
+
+#define MANTIS_GPIF_BRBYTES 0xa4
+#define MANTIS_GPIF_BRCNT (0xfff << 0)
+
+#define MANTIS_PCMCIA_RESET 0xa8
+#define MANTIS_PCMCIA_RSTVAL (0xff << 0)
+
+#define MANTIS_CARD_RESET 0xac
+
+#define MANTIS_GPIF_ADDR 0xb0
+#define MANTIS_GPIF_HIFRDWRN (0x01 << 31)
+#define MANTIS_GPIF_PCMCIAREG (0x01 << 27)
+#define MANTIS_GPIF_PCMCIAIOM (0x01 << 26)
+#define MANTIS_GPIF_HIFADDR (0xfffffff << 0)
+
+#define MANTIS_GPIF_DOUT 0xb4
+#define MANTIS_GPIF_HIFDOUT (0xfffffff << 0)
+
+#define MANTIS_GPIF_DIN 0xb8
+#define MANTIS_GPIF_HIFDIN (0xfffffff << 0)
+
+#define MANTIS_GPIF_SPARE 0xbc
+#define MANTIS_GPIF_LOGICRD (0xffff << 16)
+#define MANTIS_GPIF_LOGICRW (0xffff << 0)
+
+#endif /* __MANTIS_REG_H */
diff --git a/drivers/media/dvb/mantis/mantis_uart.c b/drivers/media/dvb/mantis/mantis_uart.c
new file mode 100644
index 00000000000..7d2f2398fa8
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_uart.c
@@ -0,0 +1,186 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/kernel.h>
+#include <linux/spinlock.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_uart.h"
+
+struct mantis_uart_params {
+ enum mantis_baud baud_rate;
+ enum mantis_parity parity;
+};
+
+static struct {
+ char string[7];
+} rates[5] = {
+ { "9600" },
+ { "19200" },
+ { "38400" },
+ { "57600" },
+ { "115200" }
+};
+
+static struct {
+ char string[5];
+} parity[3] = {
+ { "NONE" },
+ { "ODD" },
+ { "EVEN" }
+};
+
+#define UART_MAX_BUF 16
+
+int mantis_uart_read(struct mantis_pci *mantis, u8 *data)
+{
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ u32 stat = 0, i;
+
+ /* get data */
+ for (i = 0; i < (config->bytes + 1); i++) {
+
+ stat = mmread(MANTIS_UART_STAT);
+
+ if (stat & MANTIS_UART_RXFIFO_FULL) {
+ dprintk(MANTIS_ERROR, 1, "RX Fifo FULL");
+ }
+ data[i] = mmread(MANTIS_UART_RXD) & 0x3f;
+
+ dprintk(MANTIS_DEBUG, 1, "Reading ... <%02x>", data[i] & 0x3f);
+
+ if (data[i] & (1 << 7)) {
+ dprintk(MANTIS_ERROR, 1, "UART framing error");
+ return -EINVAL;
+ }
+ if (data[i] & (1 << 6)) {
+ dprintk(MANTIS_ERROR, 1, "UART parity error");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static void mantis_uart_work(struct work_struct *work)
+{
+ struct mantis_pci *mantis = container_of(work, struct mantis_pci, uart_work);
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ u8 buf[16];
+ int i;
+
+ mantis_uart_read(mantis, buf);
+
+ for (i = 0; i < (config->bytes + 1); i++)
+ dprintk(MANTIS_INFO, 1, "UART BUF:%d <%02x> ", i, buf[i]);
+
+ dprintk(MANTIS_DEBUG, 0, "\n");
+}
+
+static int mantis_uart_setup(struct mantis_pci *mantis,
+ struct mantis_uart_params *params)
+{
+ u32 reg;
+
+ mmwrite((mmread(MANTIS_UART_CTL) | (params->parity & 0x3)), MANTIS_UART_CTL);
+
+ reg = mmread(MANTIS_UART_BAUD);
+
+ switch (params->baud_rate) {
+ case MANTIS_BAUD_9600:
+ reg |= 0xd8;
+ break;
+ case MANTIS_BAUD_19200:
+ reg |= 0x6c;
+ break;
+ case MANTIS_BAUD_38400:
+ reg |= 0x36;
+ break;
+ case MANTIS_BAUD_57600:
+ reg |= 0x23;
+ break;
+ case MANTIS_BAUD_115200:
+ reg |= 0x11;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mmwrite(reg, MANTIS_UART_BAUD);
+
+ return 0;
+}
+
+int mantis_uart_init(struct mantis_pci *mantis)
+{
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ struct mantis_uart_params params;
+
+ /* default parity: */
+ params.baud_rate = config->baud_rate;
+ params.parity = config->parity;
+ dprintk(MANTIS_INFO, 1, "Initializing UART @ %sbps parity:%s",
+ rates[params.baud_rate].string,
+ parity[params.parity].string);
+
+ init_waitqueue_head(&mantis->uart_wq);
+ spin_lock_init(&mantis->uart_lock);
+
+ INIT_WORK(&mantis->uart_work, mantis_uart_work);
+
+ /* disable interrupt */
+ mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL);
+
+ mantis_uart_setup(mantis, &params);
+
+ /* default 1 byte */
+ mmwrite((mmread(MANTIS_UART_BAUD) | (config->bytes << 8)), MANTIS_UART_BAUD);
+
+ /* flush buffer */
+ mmwrite((mmread(MANTIS_UART_CTL) | MANTIS_UART_RXFLUSH), MANTIS_UART_CTL);
+
+ /* enable interrupt */
+ mmwrite(mmread(MANTIS_INT_MASK) | 0x800, MANTIS_INT_MASK);
+ mmwrite(mmread(MANTIS_UART_CTL) | MANTIS_UART_RXINT, MANTIS_UART_CTL);
+
+ schedule_work(&mantis->uart_work);
+ dprintk(MANTIS_DEBUG, 1, "UART succesfully initialized");
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_uart_init);
+
+void mantis_uart_exit(struct mantis_pci *mantis)
+{
+ /* disable interrupt */
+ mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL);
+}
+EXPORT_SYMBOL_GPL(mantis_uart_exit);
diff --git a/drivers/media/dvb/mantis/mantis_uart.h b/drivers/media/dvb/mantis/mantis_uart.h
new file mode 100644
index 00000000000..ffb62a0a5a1
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_uart.h
@@ -0,0 +1,58 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MANTIS_UART_H
+#define __MANTIS_UART_H
+
+#define MANTIS_UART_CTL 0xe0
+#define MANTIS_UART_RXINT (1 << 4)
+#define MANTIS_UART_RXFLUSH (1 << 2)
+
+#define MANTIS_UART_RXD 0xe8
+#define MANTIS_UART_BAUD 0xec
+
+#define MANTIS_UART_STAT 0xf0
+#define MANTIS_UART_RXFIFO_DATA (1 << 7)
+#define MANTIS_UART_RXFIFO_EMPTY (1 << 6)
+#define MANTIS_UART_RXFIFO_FULL (1 << 3)
+#define MANTIS_UART_FRAME_ERR (1 << 2)
+#define MANTIS_UART_PARITY_ERR (1 << 1)
+#define MANTIS_UART_RXTHRESH_INT (1 << 0)
+
+enum mantis_baud {
+ MANTIS_BAUD_9600 = 0,
+ MANTIS_BAUD_19200,
+ MANTIS_BAUD_38400,
+ MANTIS_BAUD_57600,
+ MANTIS_BAUD_115200
+};
+
+enum mantis_parity {
+ MANTIS_PARITY_NONE = 0,
+ MANTIS_PARITY_EVEN,
+ MANTIS_PARITY_ODD,
+};
+
+struct mantis_pci;
+
+extern int mantis_uart_init(struct mantis_pci *mantis);
+extern void mantis_uart_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_UART_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp1033.c b/drivers/media/dvb/mantis/mantis_vp1033.c
new file mode 100644
index 00000000000..4a723bda003
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp1033.c
@@ -0,0 +1,212 @@
+/*
+ Mantis VP-1033 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "stv0299.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp1033.h"
+#include "mantis_reg.h"
+
+u8 lgtdqcs001f_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x00,
+ 0x03, 0x00,
+ 0x04, 0x2a,
+ 0x05, 0x85,
+ 0x06, 0x02,
+ 0x07, 0x00,
+ 0x08, 0x00,
+ 0x0c, 0x01,
+ 0x0d, 0x81,
+ 0x0e, 0x44,
+ 0x0f, 0x94,
+ 0x10, 0x3c,
+ 0x11, 0x84,
+ 0x12, 0xb9,
+ 0x13, 0xb5,
+ 0x14, 0x4f,
+ 0x15, 0xc9,
+ 0x16, 0x80,
+ 0x17, 0x36,
+ 0x18, 0xfb,
+ 0x19, 0xcf,
+ 0x1a, 0xbc,
+ 0x1c, 0x2b,
+ 0x1d, 0x27,
+ 0x1e, 0x00,
+ 0x1f, 0x0b,
+ 0x20, 0xa1,
+ 0x21, 0x60,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00,
+ 0x29, 0x28,
+ 0x2a, 0x14,
+ 0x2b, 0x0f,
+ 0x2c, 0x09,
+ 0x2d, 0x05,
+ 0x31, 0x1f,
+ 0x32, 0x19,
+ 0x33, 0xfc,
+ 0x34, 0x13,
+ 0xff, 0xff,
+};
+
+#define MANTIS_MODEL_NAME "VP-1033"
+#define MANTIS_DEV_TYPE "DVB-S/DSS"
+
+int lgtdqcs001f_tuner_set(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct mantis_pci *mantis = fe->dvb->priv;
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ u8 buf[4];
+ u32 div;
+
+
+ struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf)};
+
+ div = params->frequency / 250;
+
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0x83;
+ buf[3] = 0xc0;
+
+ if (params->frequency < 1531000)
+ buf[3] |= 0x04;
+ else
+ buf[3] &= ~0x04;
+ if (i2c_transfer(adapter, &msg, 1) < 0) {
+ dprintk(MANTIS_ERROR, 1, "Write: I2C Transfer failed");
+ return -EIO;
+ }
+ msleep_interruptible(100);
+
+ return 0;
+}
+
+int lgtdqcs001f_set_symbol_rate(struct dvb_frontend *fe,
+ u32 srate, u32 ratio)
+{
+ u8 aclk = 0;
+ u8 bclk = 0;
+
+ if (srate < 1500000) {
+ aclk = 0xb7;
+ bclk = 0x47;
+ } else if (srate < 3000000) {
+ aclk = 0xb7;
+ bclk = 0x4b;
+ } else if (srate < 7000000) {
+ aclk = 0xb7;
+ bclk = 0x4f;
+ } else if (srate < 14000000) {
+ aclk = 0xb7;
+ bclk = 0x53;
+ } else if (srate < 30000000) {
+ aclk = 0xb6;
+ bclk = 0x53;
+ } else if (srate < 45000000) {
+ aclk = 0xb4;
+ bclk = 0x51;
+ }
+ stv0299_writereg(fe, 0x13, aclk);
+ stv0299_writereg(fe, 0x14, bclk);
+
+ stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg(fe, 0x21, ratio & 0xf0);
+
+ return 0;
+}
+
+struct stv0299_config lgtdqcs001f_config = {
+ .demod_address = 0x68,
+ .inittab = lgtdqcs001f_inittab,
+ .mclk = 88000000UL,
+ .invert = 0,
+ .skip_reinit = 0,
+ .volt13_op0_op1 = STV0299_VOLT13_OP0,
+ .min_delay_ms = 100,
+ .set_symbol_rate = lgtdqcs001f_set_symbol_rate,
+};
+
+static int vp1033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ int err = 0;
+
+ err = mantis_frontend_power(mantis, POWER_ON);
+ if (err == 0) {
+ mantis_frontend_soft_reset(mantis);
+ msleep(250);
+
+ dprintk(MANTIS_ERROR, 1, "Probing for STV0299 (DVB-S)");
+ fe = stv0299_attach(&lgtdqcs001f_config, adapter);
+
+ if (fe) {
+ fe->ops.tuner_ops.set_params = lgtdqcs001f_tuner_set;
+ dprintk(MANTIS_ERROR, 1, "found STV0299 DVB-S frontend @ 0x%02x",
+ lgtdqcs001f_config.demod_address);
+
+ dprintk(MANTIS_ERROR, 1, "Mantis DVB-S STV0299 frontend attach success");
+ } else {
+ return -1;
+ }
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+ }
+ mantis->fe = fe;
+ dprintk(MANTIS_ERROR, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp1033_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_204,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp1033_frontend_init,
+ .power = GPIF_A12,
+ .reset = GPIF_A13,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp1033.h b/drivers/media/dvb/mantis/mantis_vp1033.h
new file mode 100644
index 00000000000..7daaa1bf127
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp1033.h
@@ -0,0 +1,30 @@
+/*
+ Mantis VP-1033 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MANTIS_VP1033_H
+#define __MANTIS_VP1033_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_1033_DVB_S 0x0016
+
+extern struct mantis_hwconfig vp1033_config;
+
+#endif /* __MANTIS_VP1033_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp1034.c b/drivers/media/dvb/mantis/mantis_vp1034.c
new file mode 100644
index 00000000000..8e6ae558ee5
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp1034.c
@@ -0,0 +1,119 @@
+/*
+ Mantis VP-1034 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mb86a16.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp1034.h"
+#include "mantis_reg.h"
+
+struct mb86a16_config vp1034_mb86a16_config = {
+ .demod_address = 0x08,
+ .set_voltage = vp1034_set_voltage,
+};
+
+#define MANTIS_MODEL_NAME "VP-1034"
+#define MANTIS_DEV_TYPE "DVB-S/DSS"
+
+int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct mantis_pci *mantis = fe->dvb->priv;
+
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ dprintk(MANTIS_ERROR, 1, "Polarization=[13V]");
+ gpio_set_bits(mantis, 13, 1);
+ gpio_set_bits(mantis, 14, 0);
+ break;
+ case SEC_VOLTAGE_18:
+ dprintk(MANTIS_ERROR, 1, "Polarization=[18V]");
+ gpio_set_bits(mantis, 13, 1);
+ gpio_set_bits(mantis, 14, 1);
+ break;
+ case SEC_VOLTAGE_OFF:
+ dprintk(MANTIS_ERROR, 1, "Frontend (dummy) POWERDOWN");
+ break;
+ default:
+ dprintk(MANTIS_ERROR, 1, "Invalid = (%d)", (u32) voltage);
+ return -EINVAL;
+ }
+ mmwrite(0x00, MANTIS_GPIF_DOUT);
+
+ return 0;
+}
+
+static int vp1034_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ int err = 0;
+
+ err = mantis_frontend_power(mantis, POWER_ON);
+ if (err == 0) {
+ mantis_frontend_soft_reset(mantis);
+ msleep(250);
+
+ dprintk(MANTIS_ERROR, 1, "Probing for MB86A16 (DVB-S/DSS)");
+ fe = mb86a16_attach(&vp1034_mb86a16_config, adapter);
+ if (fe) {
+ dprintk(MANTIS_ERROR, 1,
+ "found MB86A16 DVB-S/DSS frontend @0x%02x",
+ vp1034_mb86a16_config.demod_address);
+
+ } else {
+ return -1;
+ }
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+ }
+ mantis->fe = fe;
+ dprintk(MANTIS_ERROR, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp1034_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_204,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp1034_frontend_init,
+ .power = GPIF_A12,
+ .reset = GPIF_A13,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp1034.h b/drivers/media/dvb/mantis/mantis_vp1034.h
new file mode 100644
index 00000000000..323f38ef8e3
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp1034.h
@@ -0,0 +1,33 @@
+/*
+ Mantis VP-1034 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MANTIS_VP1034_H
+#define __MANTIS_VP1034_H
+
+#include "dvb_frontend.h"
+#include "mantis_common.h"
+
+
+#define MANTIS_VP_1034_DVB_S 0x0014
+
+extern struct mantis_hwconfig vp1034_config;
+extern int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+
+#endif /* __MANTIS_VP1034_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp1041.c b/drivers/media/dvb/mantis/mantis_vp1041.c
new file mode 100644
index 00000000000..515346dd31d
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp1041.c
@@ -0,0 +1,358 @@
+/*
+ Mantis VP-1041 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp1041.h"
+#include "stb0899_reg.h"
+#include "stb0899_drv.h"
+#include "stb0899_cfg.h"
+#include "stb6100_cfg.h"
+#include "stb6100.h"
+#include "lnbp21.h"
+
+#define MANTIS_MODEL_NAME "VP-1041"
+#define MANTIS_DEV_TYPE "DSS/DVB-S/DVB-S2"
+
+static const struct stb0899_s1_reg vp1041_stb0899_s1_init_1[] = {
+
+ /* 0x0000000b, *//* SYSREG */
+ { STB0899_DEV_ID , 0x30 },
+ { STB0899_DISCNTRL1 , 0x32 },
+ { STB0899_DISCNTRL2 , 0x80 },
+ { STB0899_DISRX_ST0 , 0x04 },
+ { STB0899_DISRX_ST1 , 0x00 },
+ { STB0899_DISPARITY , 0x00 },
+ { STB0899_DISFIFO , 0x00 },
+ { STB0899_DISSTATUS , 0x20 },
+ { STB0899_DISF22 , 0x99 },
+ { STB0899_DISF22RX , 0xa8 },
+ /* SYSREG ? */
+ { STB0899_ACRPRESC , 0x11 },
+ { STB0899_ACRDIV1 , 0x0a },
+ { STB0899_ACRDIV2 , 0x05 },
+ { STB0899_DACR1 , 0x00 },
+ { STB0899_DACR2 , 0x00 },
+ { STB0899_OUTCFG , 0x00 },
+ { STB0899_MODECFG , 0x00 },
+ { STB0899_IRQSTATUS_3 , 0xfe },
+ { STB0899_IRQSTATUS_2 , 0x03 },
+ { STB0899_IRQSTATUS_1 , 0x7c },
+ { STB0899_IRQSTATUS_0 , 0xf4 },
+ { STB0899_IRQMSK_3 , 0xf3 },
+ { STB0899_IRQMSK_2 , 0xfc },
+ { STB0899_IRQMSK_1 , 0xff },
+ { STB0899_IRQMSK_0 , 0xff },
+ { STB0899_IRQCFG , 0x00 },
+ { STB0899_I2CCFG , 0x88 },
+ { STB0899_I2CRPT , 0x58 },
+ { STB0899_IOPVALUE5 , 0x00 },
+ { STB0899_IOPVALUE4 , 0x33 },
+ { STB0899_IOPVALUE3 , 0x6d },
+ { STB0899_IOPVALUE2 , 0x90 },
+ { STB0899_IOPVALUE1 , 0x60 },
+ { STB0899_IOPVALUE0 , 0x00 },
+ { STB0899_GPIO00CFG , 0x82 },
+ { STB0899_GPIO01CFG , 0x82 },
+ { STB0899_GPIO02CFG , 0x82 },
+ { STB0899_GPIO03CFG , 0x82 },
+ { STB0899_GPIO04CFG , 0x82 },
+ { STB0899_GPIO05CFG , 0x82 },
+ { STB0899_GPIO06CFG , 0x82 },
+ { STB0899_GPIO07CFG , 0x82 },
+ { STB0899_GPIO08CFG , 0x82 },
+ { STB0899_GPIO09CFG , 0x82 },
+ { STB0899_GPIO10CFG , 0x82 },
+ { STB0899_GPIO11CFG , 0x82 },
+ { STB0899_GPIO12CFG , 0x82 },
+ { STB0899_GPIO13CFG , 0x82 },
+ { STB0899_GPIO14CFG , 0x82 },
+ { STB0899_GPIO15CFG , 0x82 },
+ { STB0899_GPIO16CFG , 0x82 },
+ { STB0899_GPIO17CFG , 0x82 },
+ { STB0899_GPIO18CFG , 0x82 },
+ { STB0899_GPIO19CFG , 0x82 },
+ { STB0899_GPIO20CFG , 0x82 },
+ { STB0899_SDATCFG , 0xb8 },
+ { STB0899_SCLTCFG , 0xba },
+ { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */
+ { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */
+ { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */
+ { STB0899_DIRCLKCFG , 0x82 },
+ { STB0899_CLKOUT27CFG , 0x7e },
+ { STB0899_STDBYCFG , 0x82 },
+ { STB0899_CS0CFG , 0x82 },
+ { STB0899_CS1CFG , 0x82 },
+ { STB0899_DISEQCOCFG , 0x20 },
+ { STB0899_GPIO32CFG , 0x82 },
+ { STB0899_GPIO33CFG , 0x82 },
+ { STB0899_GPIO34CFG , 0x82 },
+ { STB0899_GPIO35CFG , 0x82 },
+ { STB0899_GPIO36CFG , 0x82 },
+ { STB0899_GPIO37CFG , 0x82 },
+ { STB0899_GPIO38CFG , 0x82 },
+ { STB0899_GPIO39CFG , 0x82 },
+ { STB0899_NCOARSE , 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
+ { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
+ { STB0899_FILTCTRL , 0x00 },
+ { STB0899_SYSCTRL , 0x01 },
+ { STB0899_STOPCLK1 , 0x20 },
+ { STB0899_STOPCLK2 , 0x00 },
+ { STB0899_INTBUFSTATUS , 0x00 },
+ { STB0899_INTBUFCTRL , 0x0a },
+ { 0xffff , 0xff },
+};
+
+static const struct stb0899_s1_reg vp1041_stb0899_s1_init_3[] = {
+ { STB0899_DEMOD , 0x00 },
+ { STB0899_RCOMPC , 0xc9 },
+ { STB0899_AGC1CN , 0x01 },
+ { STB0899_AGC1REF , 0x10 },
+ { STB0899_RTC , 0x23 },
+ { STB0899_TMGCFG , 0x4e },
+ { STB0899_AGC2REF , 0x34 },
+ { STB0899_TLSR , 0x84 },
+ { STB0899_CFD , 0xf7 },
+ { STB0899_ACLC , 0x87 },
+ { STB0899_BCLC , 0x94 },
+ { STB0899_EQON , 0x41 },
+ { STB0899_LDT , 0xf1 },
+ { STB0899_LDT2 , 0xe3 },
+ { STB0899_EQUALREF , 0xb4 },
+ { STB0899_TMGRAMP , 0x10 },
+ { STB0899_TMGTHD , 0x30 },
+ { STB0899_IDCCOMP , 0xfd },
+ { STB0899_QDCCOMP , 0xff },
+ { STB0899_POWERI , 0x0c },
+ { STB0899_POWERQ , 0x0f },
+ { STB0899_RCOMP , 0x6c },
+ { STB0899_AGCIQIN , 0x80 },
+ { STB0899_AGC2I1 , 0x06 },
+ { STB0899_AGC2I2 , 0x00 },
+ { STB0899_TLIR , 0x30 },
+ { STB0899_RTF , 0x7f },
+ { STB0899_DSTATUS , 0x00 },
+ { STB0899_LDI , 0xbc },
+ { STB0899_CFRM , 0xea },
+ { STB0899_CFRL , 0x31 },
+ { STB0899_NIRM , 0x2b },
+ { STB0899_NIRL , 0x80 },
+ { STB0899_ISYMB , 0x1d },
+ { STB0899_QSYMB , 0xa6 },
+ { STB0899_SFRH , 0x2f },
+ { STB0899_SFRM , 0x68 },
+ { STB0899_SFRL , 0x40 },
+ { STB0899_SFRUPH , 0x2f },
+ { STB0899_SFRUPM , 0x68 },
+ { STB0899_SFRUPL , 0x40 },
+ { STB0899_EQUAI1 , 0x02 },
+ { STB0899_EQUAQ1 , 0xff },
+ { STB0899_EQUAI2 , 0x04 },
+ { STB0899_EQUAQ2 , 0x05 },
+ { STB0899_EQUAI3 , 0x02 },
+ { STB0899_EQUAQ3 , 0xfd },
+ { STB0899_EQUAI4 , 0x03 },
+ { STB0899_EQUAQ4 , 0x07 },
+ { STB0899_EQUAI5 , 0x08 },
+ { STB0899_EQUAQ5 , 0xf5 },
+ { STB0899_DSTATUS2 , 0x00 },
+ { STB0899_VSTATUS , 0x00 },
+ { STB0899_VERROR , 0x86 },
+ { STB0899_IQSWAP , 0x2a },
+ { STB0899_ECNT1M , 0x00 },
+ { STB0899_ECNT1L , 0x00 },
+ { STB0899_ECNT2M , 0x00 },
+ { STB0899_ECNT2L , 0x00 },
+ { STB0899_ECNT3M , 0x0a },
+ { STB0899_ECNT3L , 0xad },
+ { STB0899_FECAUTO1 , 0x06 },
+ { STB0899_FECM , 0x01 },
+ { STB0899_VTH12 , 0xb0 },
+ { STB0899_VTH23 , 0x7a },
+ { STB0899_VTH34 , 0x58 },
+ { STB0899_VTH56 , 0x38 },
+ { STB0899_VTH67 , 0x34 },
+ { STB0899_VTH78 , 0x24 },
+ { STB0899_PRVIT , 0xff },
+ { STB0899_VITSYNC , 0x19 },
+ { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
+ { STB0899_TSULC , 0x42 },
+ { STB0899_RSLLC , 0x41 },
+ { STB0899_TSLPL , 0x12 },
+ { STB0899_TSCFGH , 0x0c },
+ { STB0899_TSCFGM , 0x00 },
+ { STB0899_TSCFGL , 0x00 },
+ { STB0899_TSOUT , 0x69 }, /* 0x0d for CAM */
+ { STB0899_RSSYNCDEL , 0x00 },
+ { STB0899_TSINHDELH , 0x02 },
+ { STB0899_TSINHDELM , 0x00 },
+ { STB0899_TSINHDELL , 0x00 },
+ { STB0899_TSLLSTKM , 0x1b },
+ { STB0899_TSLLSTKL , 0xb3 },
+ { STB0899_TSULSTKM , 0x00 },
+ { STB0899_TSULSTKL , 0x00 },
+ { STB0899_PCKLENUL , 0xbc },
+ { STB0899_PCKLENLL , 0xcc },
+ { STB0899_RSPCKLEN , 0xbd },
+ { STB0899_TSSTATUS , 0x90 },
+ { STB0899_ERRCTRL1 , 0xb6 },
+ { STB0899_ERRCTRL2 , 0x95 },
+ { STB0899_ERRCTRL3 , 0x8d },
+ { STB0899_DMONMSK1 , 0x27 },
+ { STB0899_DMONMSK0 , 0x03 },
+ { STB0899_DEMAPVIT , 0x5c },
+ { STB0899_PLPARM , 0x19 },
+ { STB0899_PDELCTRL , 0x48 },
+ { STB0899_PDELCTRL2 , 0x00 },
+ { STB0899_BBHCTRL1 , 0x00 },
+ { STB0899_BBHCTRL2 , 0x00 },
+ { STB0899_HYSTTHRESH , 0x77 },
+ { STB0899_MATCSTM , 0x00 },
+ { STB0899_MATCSTL , 0x00 },
+ { STB0899_UPLCSTM , 0x00 },
+ { STB0899_UPLCSTL , 0x00 },
+ { STB0899_DFLCSTM , 0x00 },
+ { STB0899_DFLCSTL , 0x00 },
+ { STB0899_SYNCCST , 0x00 },
+ { STB0899_SYNCDCSTM , 0x00 },
+ { STB0899_SYNCDCSTL , 0x00 },
+ { STB0899_ISI_ENTRY , 0x00 },
+ { STB0899_ISI_BIT_EN , 0x00 },
+ { STB0899_MATSTRM , 0xf0 },
+ { STB0899_MATSTRL , 0x02 },
+ { STB0899_UPLSTRM , 0x45 },
+ { STB0899_UPLSTRL , 0x60 },
+ { STB0899_DFLSTRM , 0xe3 },
+ { STB0899_DFLSTRL , 0x00 },
+ { STB0899_SYNCSTR , 0x47 },
+ { STB0899_SYNCDSTRM , 0x05 },
+ { STB0899_SYNCDSTRL , 0x18 },
+ { STB0899_CFGPDELSTATUS1 , 0x19 },
+ { STB0899_CFGPDELSTATUS2 , 0x2b },
+ { STB0899_BBFERRORM , 0x00 },
+ { STB0899_BBFERRORL , 0x01 },
+ { STB0899_UPKTERRORM , 0x00 },
+ { STB0899_UPKTERRORL , 0x00 },
+ { 0xffff , 0xff },
+};
+
+struct stb0899_config vp1041_stb0899_config = {
+ .init_dev = vp1041_stb0899_s1_init_1,
+ .init_s2_demod = stb0899_s2_init_2,
+ .init_s1_demod = vp1041_stb0899_s1_init_3,
+ .init_s2_fec = stb0899_s2_init_4,
+ .init_tst = stb0899_s1_init_5,
+
+ .demod_address = 0x68, /* 0xd0 >> 1 */
+
+ .xtal_freq = 27000000,
+ .inversion = IQ_SWAP_ON, /* 1 */
+
+ .lo_clk = 76500000,
+ .hi_clk = 99000000,
+
+ .esno_ave = STB0899_DVBS2_ESNO_AVE,
+ .esno_quant = STB0899_DVBS2_ESNO_QUANT,
+ .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE,
+ .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE,
+ .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD,
+ .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
+ .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
+ .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF,
+ .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
+
+ .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS,
+ .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
+ .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS,
+ .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER,
+
+ .tuner_get_frequency = stb6100_get_frequency,
+ .tuner_set_frequency = stb6100_set_frequency,
+ .tuner_set_bandwidth = stb6100_set_bandwidth,
+ .tuner_get_bandwidth = stb6100_get_bandwidth,
+ .tuner_set_rfsiggain = NULL,
+};
+
+struct stb6100_config vp1041_stb6100_config = {
+ .tuner_address = 0x60,
+ .refclock = 27000000,
+};
+
+static int vp1041_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ int err = 0;
+
+ err = mantis_frontend_power(mantis, POWER_ON);
+ if (err == 0) {
+ mantis_frontend_soft_reset(mantis);
+ msleep(250);
+ mantis->fe = stb0899_attach(&vp1041_stb0899_config, adapter);
+ if (mantis->fe) {
+ dprintk(MANTIS_ERROR, 1,
+ "found STB0899 DVB-S/DVB-S2 frontend @0x%02x",
+ vp1041_stb0899_config.demod_address);
+
+ if (stb6100_attach(mantis->fe, &vp1041_stb6100_config, adapter)) {
+ if (!lnbp21_attach(mantis->fe, adapter, 0, 0))
+ dprintk(MANTIS_ERROR, 1, "No LNBP21 found!");
+ }
+ } else {
+ return -EREMOTEIO;
+ }
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+ }
+
+
+ dprintk(MANTIS_ERROR, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp1041_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_188,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp1041_frontend_init,
+ .power = GPIF_A12,
+ .reset = GPIF_A13,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp1041.h b/drivers/media/dvb/mantis/mantis_vp1041.h
new file mode 100644
index 00000000000..1ae5b3de808
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp1041.h
@@ -0,0 +1,33 @@
+/*
+ Mantis VP-1041 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MANTIS_VP1041_H
+#define __MANTIS_VP1041_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_1041_DVB_S2 0x0031
+#define SKYSTAR_HD2_10 0x0001
+#define SKYSTAR_HD2_20 0x0003
+#define CINERGY_S2_PCI_HD 0x1179
+
+extern struct mantis_hwconfig vp1041_config;
+
+#endif /* __MANTIS_VP1041_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp2033.c b/drivers/media/dvb/mantis/mantis_vp2033.c
new file mode 100644
index 00000000000..10ce81790a8
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp2033.c
@@ -0,0 +1,187 @@
+/*
+ Mantis VP-2033 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "tda1002x.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp2033.h"
+
+#define MANTIS_MODEL_NAME "VP-2033"
+#define MANTIS_DEV_TYPE "DVB-C"
+
+struct tda1002x_config vp2033_tda1002x_cu1216_config = {
+ .demod_address = 0x18 >> 1,
+ .invert = 1,
+};
+
+struct tda10023_config vp2033_tda10023_cu1216_config = {
+ .demod_address = 0x18 >> 1,
+ .invert = 1,
+};
+
+static u8 read_pwm(struct mantis_pci *mantis)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ u8 b = 0xff;
+ u8 pwm;
+ struct i2c_msg msg[] = {
+ {.addr = 0x50, .flags = 0, .buf = &b, .len = 1},
+ {.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1}
+ };
+
+ if ((i2c_transfer(adapter, msg, 2) != 2)
+ || (pwm == 0xff))
+ pwm = 0x48;
+
+ return pwm;
+}
+
+static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct mantis_pci *mantis = fe->dvb->priv;
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ u8 buf[6];
+ struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)};
+ int i;
+
+#define CU1216_IF 36125000
+#define TUNER_MUL 62500
+
+ u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
+
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0xce;
+ buf[3] = (params->frequency < 150000000 ? 0x01 :
+ params->frequency < 445000000 ? 0x02 : 0x04);
+ buf[4] = 0xde;
+ buf[5] = 0x20;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(adapter, &msg, 1) != 1)
+ return -EIO;
+
+ /* wait for the pll lock */
+ msg.flags = I2C_M_RD;
+ msg.len = 1;
+ for (i = 0; i < 20; i++) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40))
+ break;
+
+ msleep(10);
+ }
+
+ /* switch the charge pump to the lower current */
+ msg.flags = 0;
+ msg.len = 2;
+ msg.buf = &buf[2];
+ buf[2] &= ~0x40;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(adapter, &msg, 1) != 1)
+ return -EIO;
+
+ return 0;
+}
+
+static int vp2033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ int err = 0;
+
+ err = mantis_frontend_power(mantis, POWER_ON);
+ if (err == 0) {
+ mantis_frontend_soft_reset(mantis);
+ msleep(250);
+
+ dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)");
+ fe = tda10021_attach(&vp2033_tda1002x_cu1216_config,
+ adapter,
+ read_pwm(mantis));
+
+ if (fe) {
+ dprintk(MANTIS_ERROR, 1,
+ "found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x",
+ vp2033_tda1002x_cu1216_config.demod_address);
+ } else {
+ fe = tda10023_attach(&vp2033_tda10023_cu1216_config,
+ adapter,
+ read_pwm(mantis));
+
+ if (fe) {
+ dprintk(MANTIS_ERROR, 1,
+ "found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x",
+ vp2033_tda1002x_cu1216_config.demod_address);
+ }
+ }
+
+ if (fe) {
+ fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set;
+ dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success");
+ } else {
+ return -1;
+ }
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+ }
+
+ mantis->fe = fe;
+ dprintk(MANTIS_DEBUG, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp2033_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_204,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp2033_frontend_init,
+ .power = GPIF_A12,
+ .reset = GPIF_A13,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp2033.h b/drivers/media/dvb/mantis/mantis_vp2033.h
new file mode 100644
index 00000000000..c55242b79d5
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp2033.h
@@ -0,0 +1,30 @@
+/*
+ Mantis VP-2033 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MANTIS_VP2033_H
+#define __MANTIS_VP2033_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_2033_DVB_C 0x0008
+
+extern struct mantis_hwconfig vp2033_config;
+
+#endif /* __MANTIS_VP2033_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp2040.c b/drivers/media/dvb/mantis/mantis_vp2040.c
new file mode 100644
index 00000000000..a7ca233e800
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp2040.c
@@ -0,0 +1,186 @@
+/*
+ Mantis VP-2040 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "tda1002x.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp2040.h"
+
+#define MANTIS_MODEL_NAME "VP-2040"
+#define MANTIS_DEV_TYPE "DVB-C"
+
+struct tda1002x_config vp2040_tda1002x_cu1216_config = {
+ .demod_address = 0x18 >> 1,
+ .invert = 1,
+};
+
+struct tda10023_config vp2040_tda10023_cu1216_config = {
+ .demod_address = 0x18 >> 1,
+ .invert = 1,
+};
+
+static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct mantis_pci *mantis = fe->dvb->priv;
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ u8 buf[6];
+ struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)};
+ int i;
+
+#define CU1216_IF 36125000
+#define TUNER_MUL 62500
+
+ u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
+
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0xce;
+ buf[3] = (params->frequency < 150000000 ? 0x01 :
+ params->frequency < 445000000 ? 0x02 : 0x04);
+ buf[4] = 0xde;
+ buf[5] = 0x20;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(adapter, &msg, 1) != 1)
+ return -EIO;
+
+ /* wait for the pll lock */
+ msg.flags = I2C_M_RD;
+ msg.len = 1;
+ for (i = 0; i < 20; i++) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40))
+ break;
+
+ msleep(10);
+ }
+
+ /* switch the charge pump to the lower current */
+ msg.flags = 0;
+ msg.len = 2;
+ msg.buf = &buf[2];
+ buf[2] &= ~0x40;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(adapter, &msg, 1) != 1)
+ return -EIO;
+
+ return 0;
+}
+
+static u8 read_pwm(struct mantis_pci *mantis)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ u8 b = 0xff;
+ u8 pwm;
+ struct i2c_msg msg[] = {
+ {.addr = 0x50, .flags = 0, .buf = &b, .len = 1},
+ {.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1}
+ };
+
+ if ((i2c_transfer(adapter, msg, 2) != 2)
+ || (pwm == 0xff))
+ pwm = 0x48;
+
+ return pwm;
+}
+
+static int vp2040_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ int err = 0;
+
+ err = mantis_frontend_power(mantis, POWER_ON);
+ if (err == 0) {
+ mantis_frontend_soft_reset(mantis);
+ msleep(250);
+
+ dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)");
+ fe = tda10021_attach(&vp2040_tda1002x_cu1216_config,
+ adapter,
+ read_pwm(mantis));
+
+ if (fe) {
+ dprintk(MANTIS_ERROR, 1,
+ "found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x",
+ vp2040_tda1002x_cu1216_config.demod_address);
+ } else {
+ fe = tda10023_attach(&vp2040_tda10023_cu1216_config,
+ adapter,
+ read_pwm(mantis));
+
+ if (fe) {
+ dprintk(MANTIS_ERROR, 1,
+ "found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x",
+ vp2040_tda1002x_cu1216_config.demod_address);
+ }
+ }
+
+ if (fe) {
+ fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set;
+ dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success");
+ } else {
+ return -1;
+ }
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+ }
+ mantis->fe = fe;
+ dprintk(MANTIS_DEBUG, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp2040_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_204,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp2040_frontend_init,
+ .power = GPIF_A12,
+ .reset = GPIF_A13,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp2040.h b/drivers/media/dvb/mantis/mantis_vp2040.h
new file mode 100644
index 00000000000..d125e219b68
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp2040.h
@@ -0,0 +1,32 @@
+/*
+ Mantis VP-2040 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MANTIS_VP2040_H
+#define __MANTIS_VP2040_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_2040_DVB_C 0x0043
+#define CINERGY_C 0x1178
+#define CABLESTAR_HD2 0x0002
+
+extern struct mantis_hwconfig vp2040_config;
+
+#endif /* __MANTIS_VP2040_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp3028.c b/drivers/media/dvb/mantis/mantis_vp3028.c
new file mode 100644
index 00000000000..4155c838a18
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp3028.c
@@ -0,0 +1,38 @@
+/*
+ Mantis VP-3028 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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 "mantis_common.h"
+#include "mantis_vp3028.h"
+
+struct zl10353_config mantis_vp3028_config = {
+ .demod_address = 0x0f,
+};
+
+#define MANTIS_MODEL_NAME "VP-3028"
+#define MANTIS_DEV_TYPE "DVB-T"
+
+struct mantis_hwconfig vp3028_mantis_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_188,
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp3028.h b/drivers/media/dvb/mantis/mantis_vp3028.h
new file mode 100644
index 00000000000..b07be6adc52
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp3028.h
@@ -0,0 +1,33 @@
+/*
+ Mantis VP-3028 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MANTIS_VP3028_H
+#define __MANTIS_VP3028_H
+
+#include "dvb_frontend.h"
+#include "mantis_common.h"
+#include "zl10353.h"
+
+#define MANTIS_VP_3028_DVB_T 0x0028
+
+extern struct zl10353_config mantis_vp3028_config;
+extern struct mantis_hwconfig vp3028_mantis_config;
+
+#endif /* __MANTIS_VP3028_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp3030.c b/drivers/media/dvb/mantis/mantis_vp3030.c
new file mode 100644
index 00000000000..1f433421495
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp3030.c
@@ -0,0 +1,105 @@
+/*
+ Mantis VP-3030 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "zl10353.h"
+#include "tda665x.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp3030.h"
+
+struct zl10353_config mantis_vp3030_config = {
+ .demod_address = 0x0f,
+};
+
+struct tda665x_config env57h12d5_config = {
+ .name = "ENV57H12D5 (ET-50DT)",
+ .addr = 0x60,
+ .frequency_min = 47000000,
+ .frequency_max = 862000000,
+ .frequency_offst = 3616667,
+ .ref_multiplier = 6, /* 1/6 MHz */
+ .ref_divider = 100000, /* 1/6 MHz */
+};
+
+#define MANTIS_MODEL_NAME "VP-3030"
+#define MANTIS_DEV_TYPE "DVB-T"
+
+
+static int vp3030_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ int err = 0;
+
+ gpio_set_bits(mantis, config->reset, 0);
+ msleep(100);
+ err = mantis_frontend_power(mantis, POWER_ON);
+ msleep(100);
+ gpio_set_bits(mantis, config->reset, 1);
+
+ if (err == 0) {
+ msleep(250);
+ dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)");
+ fe = zl10353_attach(&mantis_vp3030_config, adapter);
+
+ if (!fe)
+ return -1;
+
+ tda665x_attach(fe, &env57h12d5_config, adapter);
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+
+ }
+ mantis->fe = fe;
+ dprintk(MANTIS_ERROR, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp3030_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_188,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp3030_frontend_init,
+ .power = GPIF_A12,
+ .reset = GPIF_A13,
+
+ .i2c_mode = MANTIS_BYTE_MODE
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp3030.h b/drivers/media/dvb/mantis/mantis_vp3030.h
new file mode 100644
index 00000000000..5f12c426627
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp3030.h
@@ -0,0 +1,30 @@
+/*
+ Mantis VP-3030 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ 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.
+*/
+
+#ifndef __MANTIS_VP3030_H
+#define __MANTIS_VP3030_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_3030_DVB_T 0x0024
+
+extern struct mantis_hwconfig vp3030_config;
+
+#endif /* __MANTIS_VP3030_H */
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index e930a67d526..bd6214d4ab3 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -1815,6 +1815,8 @@ static int vidioc_qbuf(struct file *file, void *priv,
/* put the buffer in the 'queued' queue */
i = gspca_dev->fr_q;
gspca_dev->fr_queue[i] = index;
+ if (gspca_dev->fr_i == i)
+ gspca_dev->cur_frame = frame;
gspca_dev->fr_q = (i + 1) % gspca_dev->nframes;
PDEBUG(D_FRAM, "qbuf q:%d i:%d o:%d",
gspca_dev->fr_q,
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
index aa2f3c7e2cb..1b536f7d30c 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
+++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
@@ -48,6 +48,12 @@ static
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
}
}, {
+ .ident = "Fujitsu-Siemens Amilo Xi 2428",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428")
+ }
+ }, {
.ident = "Fujitsu-Siemens Amilo Xi 2528",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c
index 4dbb882c83d..0a6b8f07a69 100644
--- a/drivers/media/video/gspca/ov534.c
+++ b/drivers/media/video/gspca/ov534.c
@@ -1533,7 +1533,7 @@ static void setexposure_96(struct gspca_dev *gspca_dev)
static void setsharpness_96(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- u8 val;
+ s8 val;
val = sd->sharpness;
if (val < 0) { /* auto */
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
index 4cff8035614..0ca1c06652b 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -2319,7 +2319,7 @@ static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
}
}
if (avg_lum > MAX_AVG_LUM) {
- if (sd->gain - 1 >= 0) {
+ if (sd->gain >= 1) {
sd->gain--;
set_gain(gspca_dev);
}
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
index 487d4055534..96c61926d37 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
@@ -228,6 +228,7 @@ static const struct stv_init stv_bridge_init[] = {
/* This reg is written twice. Some kind of reset? */
{NULL, 0x1620, 0x80},
{NULL, 0x1620, 0x00},
+ {NULL, 0x1443, 0x00},
{NULL, 0x1423, 0x04},
{x1500, 0x1500, ARRAY_SIZE(x1500)},
{x1536, 0x1536, ARRAY_SIZE(x1536)},
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
index 716df6b15fc..306b7d75b4a 100644
--- a/drivers/media/video/gspca/sunplus.c
+++ b/drivers/media/video/gspca/sunplus.c
@@ -709,7 +709,7 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
spca504B_PollingDataReady(gspca_dev);
/* Init the cam width height with some values get on init ? */
- reg_w_riv(gspca_dev, 0x31, 0, 0x04);
+ reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
spca504B_WaitCmdStatus(gspca_dev);
spca504B_PollingDataReady(gspca_dev);
break;
@@ -807,14 +807,14 @@ static void init_ctl_reg(struct gspca_dev *gspca_dev)
default:
/* case BRIDGE_SPCA533: */
/* case BRIDGE_SPCA504B: */
- reg_w_riv(gspca_dev, 0, 0x00, 0x21ad); /* hue */
- reg_w_riv(gspca_dev, 0, 0x01, 0x21ac); /* sat/hue */
- reg_w_riv(gspca_dev, 0, 0x00, 0x21a3); /* gamma */
+ reg_w_riv(gspca_dev, 0, 0x21ad, 0x00); /* hue */
+ reg_w_riv(gspca_dev, 0, 0x21ac, 0x01); /* sat/hue */
+ reg_w_riv(gspca_dev, 0, 0x21a3, 0x00); /* gamma */
break;
case BRIDGE_SPCA536:
- reg_w_riv(gspca_dev, 0, 0x40, 0x20f5);
- reg_w_riv(gspca_dev, 0, 0x01, 0x20f4);
- reg_w_riv(gspca_dev, 0, 0x00, 0x2089);
+ reg_w_riv(gspca_dev, 0, 0x20f5, 0x40);
+ reg_w_riv(gspca_dev, 0, 0x20f4, 0x01);
+ reg_w_riv(gspca_dev, 0, 0x2089, 0x00);
break;
}
if (pollreg)
@@ -887,11 +887,11 @@ static int sd_init(struct gspca_dev *gspca_dev)
switch (sd->bridge) {
case BRIDGE_SPCA504B:
reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
- reg_w_riv(gspca_dev, 0, 0x01, 0x2306);
- reg_w_riv(gspca_dev, 0, 0x00, 0x0d04);
- reg_w_riv(gspca_dev, 0, 0x00, 0x2000);
- reg_w_riv(gspca_dev, 0, 0x13, 0x2301);
- reg_w_riv(gspca_dev, 0, 0x00, 0x2306);
+ reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01);
+ reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00);
+ reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00);
+ reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13);
+ reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00);
/* fall thru */
case BRIDGE_SPCA533:
spca504B_PollingDataReady(gspca_dev);
@@ -1000,7 +1000,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
spca504B_WaitCmdStatus(gspca_dev);
break;
default:
- reg_w_riv(gspca_dev, 0x31, 0, 0x04);
+ reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
spca504B_WaitCmdStatus(gspca_dev);
spca504B_PollingDataReady(gspca_dev);
break;
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
index c090efcd804..71921c87842 100644
--- a/drivers/media/video/gspca/vc032x.c
+++ b/drivers/media/video/gspca/vc032x.c
@@ -3009,6 +3009,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
int l;
frame = gspca_get_i_frame(gspca_dev);
+ if (frame == NULL) {
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ return;
+ }
l = frame->data_end - frame->data;
if (len > frame->v4l2_buf.length - l)
len = frame->v4l2_buf.length - l;
diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c
index 2ba14fb5b03..c167cc3de49 100644
--- a/drivers/media/video/mx1_camera.c
+++ b/drivers/media/video/mx1_camera.c
@@ -718,7 +718,7 @@ static int __init mx1_camera_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
- if (!res || !irq) {
+ if (!res || (int)irq <= 0) {
err = -ENODEV;
goto exit;
}
diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c
index 7e42989ce0e..805226e0d9c 100644
--- a/drivers/media/video/rj54n1cb0c.c
+++ b/drivers/media/video/rj54n1cb0c.c
@@ -563,7 +563,7 @@ static int rj54n1_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
struct i2c_client *client = sd->priv;
struct rj54n1 *rj54n1 = to_rj54n1(client);
struct v4l2_rect *rect = &a->c;
- unsigned int dummy, output_w, output_h,
+ unsigned int dummy = 0, output_w, output_h,
input_w = rect->width, input_h = rect->height;
int ret;
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 9f85e917f9f..a7ad7810fdd 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -420,19 +420,6 @@ int saa7134_set_dmabits(struct saa7134_dev *dev)
ctrl |= SAA7134_MAIN_CTRL_TE5;
irq |= SAA7134_IRQ1_INTE_RA2_1 |
SAA7134_IRQ1_INTE_RA2_0;
-
- /* dma: setup channel 5 (= TS) */
-
- saa_writeb(SAA7134_TS_DMA0, (dev->ts.nr_packets - 1) & 0xff);
- saa_writeb(SAA7134_TS_DMA1,
- ((dev->ts.nr_packets - 1) >> 8) & 0xff);
- /* TSNOPIT=0, TSCOLAP=0 */
- saa_writeb(SAA7134_TS_DMA2,
- (((dev->ts.nr_packets - 1) >> 16) & 0x3f) | 0x00);
- saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE);
- saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_16 |
- SAA7134_RS_CONTROL_ME |
- (dev->ts.pt_ts.dma >> 12));
}
/* set task conditions + field handling */
diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c
index 03488ba4c99..b9817d74943 100644
--- a/drivers/media/video/saa7134/saa7134-ts.c
+++ b/drivers/media/video/saa7134/saa7134-ts.c
@@ -250,6 +250,19 @@ int saa7134_ts_start(struct saa7134_dev *dev)
BUG_ON(dev->ts_started);
+ /* dma: setup channel 5 (= TS) */
+ saa_writeb(SAA7134_TS_DMA0, (dev->ts.nr_packets - 1) & 0xff);
+ saa_writeb(SAA7134_TS_DMA1,
+ ((dev->ts.nr_packets - 1) >> 8) & 0xff);
+ /* TSNOPIT=0, TSCOLAP=0 */
+ saa_writeb(SAA7134_TS_DMA2,
+ (((dev->ts.nr_packets - 1) >> 16) & 0x3f) | 0x00);
+ saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE);
+ saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_16 |
+ SAA7134_RS_CONTROL_ME |
+ (dev->ts.pt_ts.dma >> 12));
+
+ /* reset hardware TS buffers */
saa_writeb(SAA7134_TS_SERIAL1, 0x00);
saa_writeb(SAA7134_TS_SERIAL1, 0x03);
saa_writeb(SAA7134_TS_SERIAL1, 0x00);
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index d69363f0d8c..f09c7140d6b 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -1827,7 +1827,7 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
- if (!res || !irq) {
+ if (!res || (int)irq <= 0) {
dev_err(&pdev->dev, "Not enough CEU platform resources.\n");
err = -ENODEV;
goto exit;
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 0469d7a876a..ec8ef8c5560 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -1393,7 +1393,7 @@ uvc_ctrl_prune_entity(struct uvc_device *dev, struct uvc_entity *entity)
size = entity->processing.bControlSize;
for (i = 0; i < ARRAY_SIZE(blacklist); ++i) {
- if (!usb_match_id(dev->intf, &blacklist[i].id))
+ if (!usb_match_one_id(dev->intf, &blacklist[i].id))
continue;
if (blacklist[i].index >= 8 * size ||
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
index f854698c406..ea11839cba4 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -59,9 +59,9 @@
* returns immediately.
*
* When the buffer is full, the completion handler removes it from the irq
- * queue, marks it as ready (UVC_BUF_STATE_DONE) and wakes its wait queue.
+ * queue, marks it as done (UVC_BUF_STATE_DONE) and wakes its wait queue.
* At that point, any process waiting on the buffer will be woken up. If a
- * process tries to dequeue a buffer after it has been marked ready, the
+ * process tries to dequeue a buffer after it has been marked done, the
* dequeing will succeed immediately.
*
* 2. Buffers are queued, user is waiting on a buffer and the device gets
@@ -201,6 +201,7 @@ static void __uvc_query_buffer(struct uvc_buffer *buf,
break;
case UVC_BUF_STATE_QUEUED:
case UVC_BUF_STATE_ACTIVE:
+ case UVC_BUF_STATE_READY:
v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
break;
case UVC_BUF_STATE_IDLE:
@@ -295,13 +296,15 @@ static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking)
{
if (nonblocking) {
return (buf->state != UVC_BUF_STATE_QUEUED &&
- buf->state != UVC_BUF_STATE_ACTIVE)
+ buf->state != UVC_BUF_STATE_ACTIVE &&
+ buf->state != UVC_BUF_STATE_READY)
? 0 : -EAGAIN;
}
return wait_event_interruptible(buf->wait,
buf->state != UVC_BUF_STATE_QUEUED &&
- buf->state != UVC_BUF_STATE_ACTIVE);
+ buf->state != UVC_BUF_STATE_ACTIVE &&
+ buf->state != UVC_BUF_STATE_READY);
}
/*
@@ -348,6 +351,7 @@ int uvc_dequeue_buffer(struct uvc_video_queue *queue,
case UVC_BUF_STATE_IDLE:
case UVC_BUF_STATE_QUEUED:
case UVC_BUF_STATE_ACTIVE:
+ case UVC_BUF_STATE_READY:
default:
uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u "
"(driver bug?).\n", buf->state);
@@ -489,6 +493,7 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
spin_lock_irqsave(&queue->irqlock, flags);
list_del(&buf->queue);
+ buf->state = UVC_BUF_STATE_DONE;
if (!list_empty(&queue->irqqueue))
nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
queue);
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 9a9802830d4..7dcf534a0cf 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -441,7 +441,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
if (fid != stream->last_fid && buf->buf.bytesused != 0) {
uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit "
"toggled).\n");
- buf->state = UVC_BUF_STATE_DONE;
+ buf->state = UVC_BUF_STATE_READY;
return -EAGAIN;
}
@@ -470,7 +470,7 @@ static void uvc_video_decode_data(struct uvc_streaming *stream,
/* Complete the current frame if the buffer size was exceeded. */
if (len > maxlen) {
uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n");
- buf->state = UVC_BUF_STATE_DONE;
+ buf->state = UVC_BUF_STATE_READY;
}
}
@@ -482,7 +482,7 @@ static void uvc_video_decode_end(struct uvc_streaming *stream,
uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n");
if (data[0] == len)
uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n");
- buf->state = UVC_BUF_STATE_DONE;
+ buf->state = UVC_BUF_STATE_READY;
if (stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID)
stream->last_fid ^= UVC_STREAM_FID;
}
@@ -568,8 +568,7 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
uvc_video_decode_end(stream, buf, mem,
urb->iso_frame_desc[i].actual_length);
- if (buf->state == UVC_BUF_STATE_DONE ||
- buf->state == UVC_BUF_STATE_ERROR)
+ if (buf->state == UVC_BUF_STATE_READY)
buf = uvc_queue_next_buffer(&stream->queue, buf);
}
}
@@ -627,8 +626,7 @@ static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream,
if (!stream->bulk.skip_payload && buf != NULL) {
uvc_video_decode_end(stream, buf, stream->bulk.header,
stream->bulk.payload_size);
- if (buf->state == UVC_BUF_STATE_DONE ||
- buf->state == UVC_BUF_STATE_ERROR)
+ if (buf->state == UVC_BUF_STATE_READY)
buf = uvc_queue_next_buffer(&stream->queue,
buf);
}
@@ -669,7 +667,7 @@ static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream,
stream->bulk.payload_size == stream->bulk.max_payload_size) {
if (buf->buf.bytesused == stream->queue.buf_used) {
stream->queue.buf_used = 0;
- buf->state = UVC_BUF_STATE_DONE;
+ buf->state = UVC_BUF_STATE_READY;
uvc_queue_next_buffer(&stream->queue, buf);
stream->last_fid ^= UVC_STREAM_FID;
}
@@ -924,10 +922,8 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream,
static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
{
struct usb_interface *intf = stream->intf;
- struct usb_host_interface *alts;
- struct usb_host_endpoint *ep = NULL;
- int intfnum = stream->intfnum;
- unsigned int bandwidth, psize, i;
+ struct usb_host_endpoint *ep;
+ unsigned int i;
int ret;
stream->last_fid = -1;
@@ -936,6 +932,12 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
stream->bulk.payload_size = 0;
if (intf->num_altsetting > 1) {
+ struct usb_host_endpoint *best_ep = NULL;
+ unsigned int best_psize = 3 * 1024;
+ unsigned int bandwidth;
+ unsigned int uninitialized_var(altsetting);
+ int intfnum = stream->intfnum;
+
/* Isochronous endpoint, select the alternate setting. */
bandwidth = stream->ctrl.dwMaxPayloadTransferSize;
@@ -949,6 +951,9 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
}
for (i = 0; i < intf->num_altsetting; ++i) {
+ struct usb_host_interface *alts;
+ unsigned int psize;
+
alts = &intf->altsetting[i];
ep = uvc_find_endpoint(alts,
stream->header.bEndpointAddress);
@@ -958,21 +963,27 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
/* Check if the bandwidth is high enough. */
psize = le16_to_cpu(ep->desc.wMaxPacketSize);
psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
- if (psize >= bandwidth)
- break;
+ if (psize >= bandwidth && psize <= best_psize) {
+ altsetting = i;
+ best_psize = psize;
+ best_ep = ep;
+ }
}
- if (i >= intf->num_altsetting) {
+ if (best_ep == NULL) {
uvc_trace(UVC_TRACE_VIDEO, "No fast enough alt setting "
"for requested bandwidth.\n");
return -EIO;
}
- ret = usb_set_interface(stream->dev->udev, intfnum, i);
+ uvc_trace(UVC_TRACE_VIDEO, "Selecting alternate setting %u "
+ "(%u B/frame bandwidth).\n", altsetting, best_psize);
+
+ ret = usb_set_interface(stream->dev->udev, intfnum, altsetting);
if (ret < 0)
return ret;
- ret = uvc_init_video_isoc(stream, ep, gfp_flags);
+ ret = uvc_init_video_isoc(stream, best_ep, gfp_flags);
} else {
/* Bulk endpoint, proceed to URB initialization. */
ep = uvc_find_endpoint(&intf->altsetting[0],
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 7ec9a04ced5..2337585001e 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -365,8 +365,9 @@ enum uvc_buffer_state {
UVC_BUF_STATE_IDLE = 0,
UVC_BUF_STATE_QUEUED = 1,
UVC_BUF_STATE_ACTIVE = 2,
- UVC_BUF_STATE_DONE = 3,
- UVC_BUF_STATE_ERROR = 4,
+ UVC_BUF_STATE_READY = 3,
+ UVC_BUF_STATE_DONE = 4,
+ UVC_BUF_STATE_ERROR = 5,
};
struct uvc_buffer {
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index ca2f2c4ff05..8f0d18409ed 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -11,9 +11,9 @@ obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o
obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
-obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o
-obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o
-obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o
+obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o
+obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o
+obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o
obj-$(CONFIG_MFD_WM8400) += wm8400-core.o
wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index e22128c3e9a..95c1e6bd172 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -80,6 +80,7 @@ struct asic3 {
u16 irq_bothedge[4];
struct gpio_chip gpio;
struct device *dev;
+ void __iomem *tmio_cnf;
struct asic3_clk clocks[ARRAY_SIZE(asic3_clk_init)];
};
@@ -685,8 +686,24 @@ static struct mfd_cell asic3_cell_ds1wm = {
.resources = ds1wm_resources,
};
+static void asic3_mmc_pwr(struct platform_device *pdev, int state)
+{
+ struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
+
+ tmio_core_mmc_pwr(asic->tmio_cnf, 1 - asic->bus_shift, state);
+}
+
+static void asic3_mmc_clk_div(struct platform_device *pdev, int state)
+{
+ struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
+
+ tmio_core_mmc_clk_div(asic->tmio_cnf, 1 - asic->bus_shift, state);
+}
+
static struct tmio_mmc_data asic3_mmc_data = {
- .hclk = 24576000,
+ .hclk = 24576000,
+ .set_pwr = asic3_mmc_pwr,
+ .set_clk_div = asic3_mmc_clk_div,
};
static struct resource asic3_mmc_resources[] = {
@@ -696,11 +713,6 @@ static struct resource asic3_mmc_resources[] = {
.flags = IORESOURCE_MEM,
},
{
- .start = ASIC3_SD_CONFIG_BASE,
- .end = ASIC3_SD_CONFIG_BASE + 0x1ff,
- .flags = IORESOURCE_MEM,
- },
- {
.start = 0,
.end = 0,
.flags = IORESOURCE_IRQ,
@@ -743,6 +755,10 @@ static int asic3_mmc_enable(struct platform_device *pdev)
asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF),
ASIC3_SDHWCTRL_SDPWR, 1);
+ /* ASIC3_SD_CTRL_BASE assumes 32-bit addressing, TMIO is 16-bit */
+ tmio_core_mmc_enable(asic->tmio_cnf, 1 - asic->bus_shift,
+ ASIC3_SD_CTRL_BASE >> 1);
+
return 0;
}
@@ -797,10 +813,15 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
asic3_cell_ds1wm.data_size = sizeof(asic3_cell_ds1wm);
/* MMC */
+ asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) +
+ mem_sdio->start, 0x400 >> asic->bus_shift);
+ if (!asic->tmio_cnf) {
+ ret = -ENOMEM;
+ dev_dbg(asic->dev, "Couldn't ioremap SD_CONFIG\n");
+ goto out;
+ }
asic3_mmc_resources[0].start >>= asic->bus_shift;
asic3_mmc_resources[0].end >>= asic->bus_shift;
- asic3_mmc_resources[1].start >>= asic->bus_shift;
- asic3_mmc_resources[1].end >>= asic->bus_shift;
asic3_cell_mmc.platform_data = &asic3_cell_mmc;
asic3_cell_mmc.data_size = sizeof(asic3_cell_mmc);
@@ -820,7 +841,10 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
static void asic3_mfd_remove(struct platform_device *pdev)
{
+ struct asic3 *asic = platform_get_drvdata(pdev);
+
mfd_remove_devices(&pdev->dev);
+ iounmap(asic->tmio_cnf);
}
/* Core */
diff --git a/drivers/mfd/mc13783-core.c b/drivers/mfd/mc13783-core.c
index a1ade2324ea..735c8a4d164 100644
--- a/drivers/mfd/mc13783-core.c
+++ b/drivers/mfd/mc13783-core.c
@@ -619,6 +619,8 @@ err_revision:
}
/* This should go away (END) */
+ mc13783_unlock(mc13783);
+
if (pdata->flags & MC13783_USE_ADC)
mc13783_add_subdevice(mc13783, "mc13783-adc");
@@ -641,8 +643,6 @@ err_revision:
if (pdata->flags & MC13783_USE_TOUCHSCREEN)
mc13783_add_subdevice(mc13783, "mc13783-ts");
- mc13783_unlock(mc13783);
-
return 0;
}
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c
index 0a255c1f1ce..bcf4687d4af 100644
--- a/drivers/mfd/t7l66xb.c
+++ b/drivers/mfd/t7l66xb.c
@@ -38,6 +38,19 @@ enum {
T7L66XB_CELL_MMC,
};
+static const struct resource t7l66xb_mmc_resources[] = {
+ {
+ .start = 0x800,
+ .end = 0x9ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_T7L66XB_MMC,
+ .end = IRQ_T7L66XB_MMC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
#define SCR_REVID 0x08 /* b Revision ID */
#define SCR_IMR 0x42 /* b Interrupt Mask */
#define SCR_DEV_CTL 0xe0 /* b Device control */
@@ -83,6 +96,9 @@ static int t7l66xb_mmc_enable(struct platform_device *mmc)
spin_unlock_irqrestore(&t7l66xb->lock, flags);
+ tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0,
+ t7l66xb_mmc_resources[0].start & 0xfffe);
+
return 0;
}
@@ -106,28 +122,28 @@ static int t7l66xb_mmc_disable(struct platform_device *mmc)
return 0;
}
+static void t7l66xb_mmc_pwr(struct platform_device *mmc, int state)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_pwr(t7l66xb->scr + 0x200, 0, state);
+}
+
+static void t7l66xb_mmc_clk_div(struct platform_device *mmc, int state)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_clk_div(t7l66xb->scr + 0x200, 0, state);
+}
+
/*--------------------------------------------------------------------------*/
static struct tmio_mmc_data t7166xb_mmc_data = {
.hclk = 24000000,
-};
-
-static const struct resource t7l66xb_mmc_resources[] = {
- {
- .start = 0x800,
- .end = 0x9ff,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = 0x200,
- .end = 0x2ff,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = IRQ_T7L66XB_MMC,
- .end = IRQ_T7L66XB_MMC,
- .flags = IORESOURCE_IRQ,
- },
+ .set_pwr = t7l66xb_mmc_pwr,
+ .set_clk_div = t7l66xb_mmc_clk_div,
};
static const struct resource t7l66xb_nand_resources[] = {
@@ -282,6 +298,9 @@ static int t7l66xb_resume(struct platform_device *dev)
if (pdata && pdata->resume)
pdata->resume(dev);
+ tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0,
+ t7l66xb_mmc_resources[0].start & 0xfffe);
+
return 0;
}
#else
diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c
index 3280ab33f88..5c7f04343d5 100644
--- a/drivers/mfd/tc6387xb.c
+++ b/drivers/mfd/tc6387xb.c
@@ -22,28 +22,52 @@ enum {
TC6387XB_CELL_MMC,
};
+struct tc6387xb {
+ void __iomem *scr;
+ struct clk *clk32k;
+ struct resource rscr;
+};
+
+static struct resource tc6387xb_mmc_resources[] = {
+ {
+ .start = 0x800,
+ .end = 0x9ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = 0,
+ .end = 0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+/*--------------------------------------------------------------------------*/
+
#ifdef CONFIG_PM
static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state)
{
- struct clk *clk32k = platform_get_drvdata(dev);
+ struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
if (pdata && pdata->suspend)
pdata->suspend(dev);
- clk_disable(clk32k);
+ clk_disable(tc6387xb->clk32k);
return 0;
}
static int tc6387xb_resume(struct platform_device *dev)
{
- struct clk *clk32k = platform_get_drvdata(dev);
+ struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
- clk_enable(clk32k);
+ clk_enable(tc6387xb->clk32k);
if (pdata && pdata->resume)
pdata->resume(dev);
+ tmio_core_mmc_resume(tc6387xb->scr + 0x200, 0,
+ tc6387xb_mmc_resources[0].start & 0xfffe);
+
return 0;
}
#else
@@ -53,12 +77,32 @@ static int tc6387xb_resume(struct platform_device *dev)
/*--------------------------------------------------------------------------*/
+static void tc6387xb_mmc_pwr(struct platform_device *mmc, int state)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_pwr(tc6387xb->scr + 0x200, 0, state);
+}
+
+static void tc6387xb_mmc_clk_div(struct platform_device *mmc, int state)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_clk_div(tc6387xb->scr + 0x200, 0, state);
+}
+
+
static int tc6387xb_mmc_enable(struct platform_device *mmc)
{
struct platform_device *dev = to_platform_device(mmc->dev.parent);
- struct clk *clk32k = platform_get_drvdata(dev);
+ struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
- clk_enable(clk32k);
+ clk_enable(tc6387xb->clk32k);
+
+ tmio_core_mmc_enable(tc6387xb->scr + 0x200, 0,
+ tc6387xb_mmc_resources[0].start & 0xfffe);
return 0;
}
@@ -66,36 +110,20 @@ static int tc6387xb_mmc_enable(struct platform_device *mmc)
static int tc6387xb_mmc_disable(struct platform_device *mmc)
{
struct platform_device *dev = to_platform_device(mmc->dev.parent);
- struct clk *clk32k = platform_get_drvdata(dev);
+ struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
- clk_disable(clk32k);
+ clk_disable(tc6387xb->clk32k);
return 0;
}
-/*--------------------------------------------------------------------------*/
-
static struct tmio_mmc_data tc6387xb_mmc_data = {
.hclk = 24000000,
+ .set_pwr = tc6387xb_mmc_pwr,
+ .set_clk_div = tc6387xb_mmc_clk_div,
};
-static struct resource tc6387xb_mmc_resources[] = {
- {
- .start = 0x800,
- .end = 0x9ff,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = 0x200,
- .end = 0x2ff,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = 0,
- .end = 0,
- .flags = IORESOURCE_IRQ,
- },
-};
+/*--------------------------------------------------------------------------*/
static struct mfd_cell tc6387xb_cells[] = {
[TC6387XB_CELL_MMC] = {
@@ -111,8 +139,9 @@ static struct mfd_cell tc6387xb_cells[] = {
static int tc6387xb_probe(struct platform_device *dev)
{
struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
- struct resource *iomem;
+ struct resource *iomem, *rscr;
struct clk *clk32k;
+ struct tc6387xb *tc6387xb;
int irq, ret;
iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
@@ -120,18 +149,40 @@ static int tc6387xb_probe(struct platform_device *dev)
return -EINVAL;
}
+ tc6387xb = kzalloc(sizeof *tc6387xb, GFP_KERNEL);
+ if (!tc6387xb)
+ return -ENOMEM;
+
ret = platform_get_irq(dev, 0);
if (ret >= 0)
irq = ret;
else
- goto err_resource;
+ goto err_no_irq;
clk32k = clk_get(&dev->dev, "CLK_CK32K");
if (IS_ERR(clk32k)) {
ret = PTR_ERR(clk32k);
+ goto err_no_clk;
+ }
+
+ rscr = &tc6387xb->rscr;
+ rscr->name = "tc6387xb-core";
+ rscr->start = iomem->start;
+ rscr->end = iomem->start + 0xff;
+ rscr->flags = IORESOURCE_MEM;
+
+ ret = request_resource(iomem, rscr);
+ if (ret)
goto err_resource;
+
+ tc6387xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1);
+ if (!tc6387xb->scr) {
+ ret = -ENOMEM;
+ goto err_ioremap;
}
- platform_set_drvdata(dev, clk32k);
+
+ tc6387xb->clk32k = clk32k;
+ platform_set_drvdata(dev, tc6387xb);
if (pdata && pdata->enable)
pdata->enable(dev);
@@ -149,8 +200,13 @@ static int tc6387xb_probe(struct platform_device *dev)
if (!ret)
return 0;
- clk_put(clk32k);
+err_ioremap:
+ release_resource(&tc6387xb->rscr);
err_resource:
+ clk_put(clk32k);
+err_no_clk:
+err_no_irq:
+ kfree(tc6387xb);
return ret;
}
@@ -195,3 +251,4 @@ MODULE_DESCRIPTION("Toshiba TC6387XB core driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Ian Molton");
MODULE_ALIAS("platform:tc6387xb");
+
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
index 1429a7341a9..4bc5a08a2b0 100644
--- a/drivers/mfd/tc6393xb.c
+++ b/drivers/mfd/tc6393xb.c
@@ -136,10 +136,6 @@ static int tc6393xb_nand_enable(struct platform_device *nand)
return 0;
}
-static struct tmio_mmc_data tc6393xb_mmc_data = {
- .hclk = 24000000,
-};
-
static struct resource __devinitdata tc6393xb_nand_resources[] = {
{
.start = 0x1000,
@@ -165,11 +161,6 @@ static struct resource __devinitdata tc6393xb_mmc_resources[] = {
.flags = IORESOURCE_MEM,
},
{
- .start = 0x200,
- .end = 0x2ff,
- .flags = IORESOURCE_MEM,
- },
- {
.start = IRQ_TC6393_MMC,
.end = IRQ_TC6393_MMC,
.flags = IORESOURCE_IRQ,
@@ -346,6 +337,50 @@ int tc6393xb_lcd_mode(struct platform_device *fb,
}
EXPORT_SYMBOL(tc6393xb_lcd_mode);
+static int tc6393xb_mmc_enable(struct platform_device *mmc)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_enable(tc6393xb->scr + 0x200, 0,
+ tc6393xb_mmc_resources[0].start & 0xfffe);
+
+ return 0;
+}
+
+static int tc6393xb_mmc_resume(struct platform_device *mmc)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_resume(tc6393xb->scr + 0x200, 0,
+ tc6393xb_mmc_resources[0].start & 0xfffe);
+
+ return 0;
+}
+
+static void tc6393xb_mmc_pwr(struct platform_device *mmc, int state)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_pwr(tc6393xb->scr + 0x200, 0, state);
+}
+
+static void tc6393xb_mmc_clk_div(struct platform_device *mmc, int state)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_clk_div(tc6393xb->scr + 0x200, 0, state);
+}
+
+static struct tmio_mmc_data tc6393xb_mmc_data = {
+ .hclk = 24000000,
+ .set_pwr = tc6393xb_mmc_pwr,
+ .set_clk_div = tc6393xb_mmc_clk_div,
+};
+
static struct mfd_cell __devinitdata tc6393xb_cells[] = {
[TC6393XB_CELL_NAND] = {
.name = "tmio-nand",
@@ -355,6 +390,8 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = {
},
[TC6393XB_CELL_MMC] = {
.name = "tmio-mmc",
+ .enable = tc6393xb_mmc_enable,
+ .resume = tc6393xb_mmc_resume,
.driver_data = &tc6393xb_mmc_data,
.num_resources = ARRAY_SIZE(tc6393xb_mmc_resources),
.resources = tc6393xb_mmc_resources,
@@ -836,3 +873,4 @@ MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov and Dirk Opfer");
MODULE_DESCRIPTION("tc6393xb Toshiba Mobile IO Controller");
MODULE_ALIAS("platform:tc6393xb");
+
diff --git a/drivers/mfd/tmio_core.c b/drivers/mfd/tmio_core.c
new file mode 100644
index 00000000000..eddc19ae464
--- /dev/null
+++ b/drivers/mfd/tmio_core.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright(c) 2009 Ian Molton <spyro@f2s.com>
+ *
+ * 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.
+ */
+
+#include <linux/mfd/tmio.h>
+
+int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base)
+{
+ /* Enable the MMC/SD Control registers */
+ sd_config_write16(cnf, shift, CNF_CMD, SDCREN);
+ sd_config_write32(cnf, shift, CNF_CTL_BASE, base & 0xfffe);
+
+ /* Disable SD power during suspend */
+ sd_config_write8(cnf, shift, CNF_PWR_CTL_3, 0x01);
+
+ /* The below is required but why? FIXME */
+ sd_config_write8(cnf, shift, CNF_STOP_CLK_CTL, 0x1f);
+
+ /* Power down SD bus */
+ sd_config_write8(cnf, shift, CNF_PWR_CTL_2, 0x00);
+
+ return 0;
+}
+EXPORT_SYMBOL(tmio_core_mmc_enable);
+
+int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base)
+{
+
+ /* Enable the MMC/SD Control registers */
+ sd_config_write16(cnf, shift, CNF_CMD, SDCREN);
+ sd_config_write32(cnf, shift, CNF_CTL_BASE, base & 0xfffe);
+
+ return 0;
+}
+EXPORT_SYMBOL(tmio_core_mmc_resume);
+
+void tmio_core_mmc_pwr(void __iomem *cnf, int shift, int state)
+{
+ sd_config_write8(cnf, shift, CNF_PWR_CTL_2, state ? 0x02 : 0x00);
+}
+EXPORT_SYMBOL(tmio_core_mmc_pwr);
+
+void tmio_core_mmc_clk_div(void __iomem *cnf, int shift, int state)
+{
+ sd_config_write8(cnf, shift, CNF_SD_CLK_MODE, state ? 1 : 0);
+}
+EXPORT_SYMBOL(tmio_core_mmc_clk_div);
+
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c
index 8485a701806..9a970bd6877 100644
--- a/drivers/mfd/wm8350-core.c
+++ b/drivers/mfd/wm8350-core.c
@@ -134,8 +134,7 @@ static inline int is_reg_locked(struct wm8350 *wm8350, u8 reg)
wm8350->reg_cache[WM8350_SECURITY] == WM8350_UNLOCK_KEY)
return 0;
- if ((reg == WM8350_GPIO_CONFIGURATION_I_O) ||
- (reg >= WM8350_GPIO_FUNCTION_SELECT_1 &&
+ if ((reg >= WM8350_GPIO_FUNCTION_SELECT_1 &&
reg <= WM8350_GPIO_FUNCTION_SELECT_4) ||
(reg >= WM8350_BATTERY_CHARGER_CONTROL_1 &&
reg <= WM8350_BATTERY_CHARGER_CONTROL_3))
diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c
index c8df547c474..9025f29e270 100644
--- a/drivers/mfd/wm8350-irq.c
+++ b/drivers/mfd/wm8350-irq.c
@@ -434,7 +434,7 @@ int wm8350_register_irq(struct wm8350 *wm8350, int irq,
irq_handler_t handler, unsigned long flags,
const char *name, void *data)
{
- if (irq < 0 || irq > WM8350_NUM_IRQ || !handler)
+ if (irq < 0 || irq >= WM8350_NUM_IRQ || !handler)
return -EINVAL;
if (wm8350->irq[irq].handler)
@@ -453,7 +453,7 @@ EXPORT_SYMBOL_GPL(wm8350_register_irq);
int wm8350_free_irq(struct wm8350 *wm8350, int irq)
{
- if (irq < 0 || irq > WM8350_NUM_IRQ)
+ if (irq < 0 || irq >= WM8350_NUM_IRQ)
return -EINVAL;
wm8350_mask_irq(wm8350, irq);
diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
index 7cccc852374..e22c3fa3516 100644
--- a/drivers/mmc/host/tmio_mmc.c
+++ b/drivers/mmc/host/tmio_mmc.c
@@ -46,7 +46,9 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock)
clk |= 0x100;
}
- sd_config_write8(host, CNF_SD_CLK_MODE, clk >> 22);
+ if (host->set_clk_div)
+ host->set_clk_div(host->pdev, (clk>>22) & 1);
+
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x1ff);
}
@@ -427,12 +429,13 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
/* Power sequence - OFF -> ON -> UP */
switch (ios->power_mode) {
case MMC_POWER_OFF: /* power down SD bus */
- sd_config_write8(host, CNF_PWR_CTL_2, 0x00);
+ if (host->set_pwr)
+ host->set_pwr(host->pdev, 0);
tmio_mmc_clk_stop(host);
break;
case MMC_POWER_ON: /* power up SD bus */
-
- sd_config_write8(host, CNF_PWR_CTL_2, 0x02);
+ if (host->set_pwr)
+ host->set_pwr(host->pdev, 1);
break;
case MMC_POWER_UP: /* start bus clock */
tmio_mmc_clk_start(host);
@@ -485,21 +488,15 @@ static int tmio_mmc_resume(struct platform_device *dev)
{
struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data;
struct mmc_host *mmc = platform_get_drvdata(dev);
- struct tmio_mmc_host *host = mmc_priv(mmc);
int ret = 0;
/* Tell the MFD core we are ready to be enabled */
- if (cell->enable) {
- ret = cell->enable(dev);
+ if (cell->resume) {
+ ret = cell->resume(dev);
if (ret)
goto out;
}
- /* Enable the MMC/SD Control registers */
- sd_config_write16(host, CNF_CMD, SDCREN);
- sd_config_write32(host, CNF_CTL_BASE,
- (dev->resource[0].start >> host->bus_shift) & 0xfffe);
-
mmc_resume_host(mmc);
out:
@@ -514,17 +511,16 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
{
struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data;
struct tmio_mmc_data *pdata;
- struct resource *res_ctl, *res_cnf;
+ struct resource *res_ctl;
struct tmio_mmc_host *host;
struct mmc_host *mmc;
int ret = -EINVAL;
- if (dev->num_resources != 3)
+ if (dev->num_resources != 2)
goto out;
res_ctl = platform_get_resource(dev, IORESOURCE_MEM, 0);
- res_cnf = platform_get_resource(dev, IORESOURCE_MEM, 1);
- if (!res_ctl || !res_cnf)
+ if (!res_ctl)
goto out;
pdata = cell->driver_data;
@@ -539,8 +535,12 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
host = mmc_priv(mmc);
host->mmc = mmc;
+ host->pdev = dev;
platform_set_drvdata(dev, mmc);
+ host->set_pwr = pdata->set_pwr;
+ host->set_clk_div = pdata->set_clk_div;
+
/* SD control register space size is 0x200, 0x400 for bus_shift=1 */
host->bus_shift = resource_size(res_ctl) >> 10;
@@ -548,10 +548,6 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
if (!host->ctl)
goto host_free;
- host->cnf = ioremap(res_cnf->start, resource_size(res_cnf));
- if (!host->cnf)
- goto unmap_ctl;
-
mmc->ops = &tmio_mmc_ops;
mmc->caps = MMC_CAP_4_BIT_DATA;
mmc->f_max = pdata->hclk;
@@ -562,23 +558,9 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
if (cell->enable) {
ret = cell->enable(dev);
if (ret)
- goto unmap_cnf;
+ goto unmap_ctl;
}
- /* Enable the MMC/SD Control registers */
- sd_config_write16(host, CNF_CMD, SDCREN);
- sd_config_write32(host, CNF_CTL_BASE,
- (dev->resource[0].start >> host->bus_shift) & 0xfffe);
-
- /* Disable SD power during suspend */
- sd_config_write8(host, CNF_PWR_CTL_3, 0x01);
-
- /* The below is required but why? FIXME */
- sd_config_write8(host, CNF_STOP_CLK_CTL, 0x1f);
-
- /* Power down SD bus*/
- sd_config_write8(host, CNF_PWR_CTL_2, 0x00);
-
tmio_mmc_clk_stop(host);
reset(host);
@@ -586,14 +568,14 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
if (ret >= 0)
host->irq = ret;
else
- goto unmap_cnf;
+ goto unmap_ctl;
disable_mmc_irqs(host, TMIO_MASK_ALL);
ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED |
IRQF_TRIGGER_FALLING, dev_name(&dev->dev), host);
if (ret)
- goto unmap_cnf;
+ goto unmap_ctl;
mmc_add_host(mmc);
@@ -605,8 +587,6 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
return 0;
-unmap_cnf:
- iounmap(host->cnf);
unmap_ctl:
iounmap(host->ctl);
host_free:
@@ -626,7 +606,6 @@ static int __devexit tmio_mmc_remove(struct platform_device *dev)
mmc_remove_host(mmc);
free_irq(host->irq, host);
iounmap(host->ctl);
- iounmap(host->cnf);
mmc_free_host(mmc);
}
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index 9fa99859497..692dc23363b 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -11,26 +11,6 @@
#include <linux/highmem.h>
-#define CNF_CMD 0x04
-#define CNF_CTL_BASE 0x10
-#define CNF_INT_PIN 0x3d
-#define CNF_STOP_CLK_CTL 0x40
-#define CNF_GCLK_CTL 0x41
-#define CNF_SD_CLK_MODE 0x42
-#define CNF_PIN_STATUS 0x44
-#define CNF_PWR_CTL_1 0x48
-#define CNF_PWR_CTL_2 0x49
-#define CNF_PWR_CTL_3 0x4a
-#define CNF_CARD_DETECT_MODE 0x4c
-#define CNF_SD_SLOT 0x50
-#define CNF_EXT_GCLK_CTL_1 0xf0
-#define CNF_EXT_GCLK_CTL_2 0xf1
-#define CNF_EXT_GCLK_CTL_3 0xf9
-#define CNF_SD_LED_EN_1 0xfa
-#define CNF_SD_LED_EN_2 0xfe
-
-#define SDCREN 0x2 /* Enable access to MMC CTL regs. (flag in COMMAND_REG)*/
-
#define CTL_SD_CMD 0x00
#define CTL_ARG_REG 0x04
#define CTL_STOP_INTERNAL_ACTION 0x08
@@ -110,7 +90,6 @@
struct tmio_mmc_host {
- void __iomem *cnf;
void __iomem *ctl;
unsigned long bus_shift;
struct mmc_command *cmd;
@@ -119,10 +98,16 @@ struct tmio_mmc_host {
struct mmc_host *mmc;
int irq;
+ /* Callbacks for clock / power control */
+ void (*set_pwr)(struct platform_device *host, int state);
+ void (*set_clk_div)(struct platform_device *host, int state);
+
/* pio related stuff */
struct scatterlist *sg_ptr;
unsigned int sg_len;
unsigned int sg_off;
+
+ struct platform_device *pdev;
};
#include <linux/io.h>
@@ -163,25 +148,6 @@ static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr,
writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift));
}
-static inline void sd_config_write8(struct tmio_mmc_host *host, int addr,
- u8 val)
-{
- writeb(val, host->cnf + (addr << host->bus_shift));
-}
-
-static inline void sd_config_write16(struct tmio_mmc_host *host, int addr,
- u16 val)
-{
- writew(val, host->cnf + (addr << host->bus_shift));
-}
-
-static inline void sd_config_write32(struct tmio_mmc_host *host, int addr,
- u32 val)
-{
- writew(val, host->cnf + (addr << host->bus_shift));
- writew(val >> 16, host->cnf + ((addr + 2) << host->bus_shift));
-}
-
#include <linux/scatterlist.h>
#include <linux/blkdev.h>
diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c
index 36ede02ceac..b5496a19d96 100644
--- a/drivers/serial/8250_pnp.c
+++ b/drivers/serial/8250_pnp.c
@@ -354,6 +354,8 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "FUJ02E5", 0 },
/* Fujitsu P-series tablet PC device */
{ "FUJ02E6", 0 },
+ /* Fujitsu Wacom 2FGT Tablet PC device */
+ { "FUJ02E7", 0 },
/*
* LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 in
* disguise)
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index 0700cd10b97..683e66f18e8 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -411,6 +411,17 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap)
goto ack_tx_int;
}
+ /* Under some circumstances, we see interrupts reported for
+ * a closed channel. The interrupt mask in R1 is clear, but
+ * R3 still signals the interrupts and we see them when taking
+ * an interrupt for the other channel (this could be a qemu
+ * bug but since the ESCC doc doesn't specify precsiely whether
+ * R3 interrup status bits are masked by R1 interrupt enable
+ * bits, better safe than sorry). --BenH.
+ */
+ if (!ZS_IS_OPEN(uap))
+ goto ack_tx_int;
+
if (uap->port.x_char) {
uap->flags |= PMACZILOG_FLAG_TX_ACTIVE;
write_zsdata(uap, uap->port.x_char);
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 37f0de9dd9c..42f3333c4ad 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -1052,7 +1052,18 @@ static void __devinit sci_init_single(struct platform_device *dev,
sci_port->port.ops = &sci_uart_ops;
sci_port->port.iotype = UPIO_MEM;
sci_port->port.line = index;
- sci_port->port.fifosize = 1;
+
+ switch (p->type) {
+ case PORT_SCIFA:
+ sci_port->port.fifosize = 64;
+ break;
+ case PORT_SCIF:
+ sci_port->port.fifosize = 16;
+ break;
+ default:
+ sci_port->port.fifosize = 1;
+ break;
+ }
if (dev) {
sci_port->iclk = p->clk ? clk_get(&dev->dev, p->clk) : NULL;
diff --git a/drivers/staging/cx25821/cx25821-medusa-video.c b/drivers/staging/cx25821/cx25821-medusa-video.c
index e4df8134f05..1eb079b3d42 100644
--- a/drivers/staging/cx25821/cx25821-medusa-video.c
+++ b/drivers/staging/cx25821/cx25821-medusa-video.c
@@ -860,10 +860,8 @@ int medusa_video_init(struct cx25821_dev *dev)
ret_val = medusa_set_videostandard(dev);
- if (ret_val < 0) {
- mutex_unlock(&dev->lock);
+ if (ret_val < 0)
return -EINVAL;
- }
return 1;
}
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
index adf9632c6b1..53cb722c45a 100644
--- a/drivers/video/s3c-fb.c
+++ b/drivers/video/s3c-fb.c
@@ -211,21 +211,23 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
/**
* s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock.
- * @id: window id.
* @sfb: The hardware state.
* @pixclock: The pixel clock wanted, in picoseconds.
*
* Given the specified pixel clock, work out the necessary divider to get
* close to the output frequency.
*/
-static int s3c_fb_calc_pixclk(unsigned char id, struct s3c_fb *sfb, unsigned int pixclk)
+static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
{
- struct s3c_fb_pd_win *win = sfb->pdata->win[id];
unsigned long clk = clk_get_rate(sfb->bus_clk);
+ unsigned long long tmp;
unsigned int result;
- pixclk *= win->win_mode.refresh;
- result = clk / pixclk;
+ tmp = (unsigned long long)clk;
+ tmp *= pixclk;
+
+ do_div(tmp, 1000000000UL);
+ result = (unsigned int)tmp / 1000;
dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n",
pixclk, clk, result, clk / result);
@@ -301,7 +303,7 @@ static int s3c_fb_set_par(struct fb_info *info)
/* use window 0 as the basis for the lcd output timings */
if (win_no == 0) {
- clkdiv = s3c_fb_calc_pixclk(win_no, sfb, var->pixclock);
+ clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock);
data = sfb->pdata->vidcon0;
data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c
index 9d4f3a49ba4..d5077dfa9e0 100644
--- a/drivers/video/via/accel.c
+++ b/drivers/video/via/accel.c
@@ -137,7 +137,7 @@ static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height,
tmp, dst_pitch);
return -EINVAL;
}
- tmp = (tmp >> 3) | (dst_pitch << (16 - 3));
+ tmp = VIA_PITCH_ENABLE | (tmp >> 3) | (dst_pitch << (16 - 3));
writel(tmp, engine + 0x38);
if (op == VIA_BITBLT_FILL)
@@ -352,6 +352,9 @@ int viafb_init_engine(struct fb_info *info)
viapar->shared->vq_vram_addr = viapar->fbmem_free;
viapar->fbmem_used += VQ_SIZE;
+ /* Init 2D engine reg to reset 2D engine */
+ writel(0x0, engine + VIA_REG_KEYCONTROL);
+
/* Init AGP and VQ regs */
switch (chip_name) {
case UNICHROME_K8M890:
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index d8df17a7d5f..3028e7ddc3b 100644
--- a/drivers/video/via/viafbdev.c
+++ b/drivers/video/via/viafbdev.c
@@ -177,16 +177,15 @@ static int viafb_set_par(struct fb_info *info)
}
if (vmode_index != VIA_RES_INVALID) {
- viafb_setmode(vmode_index, info->var.xres, info->var.yres,
- info->var.bits_per_pixel, vmode_index1,
- viafb_second_xres, viafb_second_yres, viafb_bpp1);
-
viafb_update_fix(info);
viafb_bpp = info->var.bits_per_pixel;
if (info->var.accel_flags & FB_ACCELF_TEXT)
info->flags &= ~FBINFO_HWACCEL_DISABLED;
else
info->flags |= FBINFO_HWACCEL_DISABLED;
+ viafb_setmode(vmode_index, info->var.xres, info->var.yres,
+ info->var.bits_per_pixel, vmode_index1,
+ viafb_second_xres, viafb_second_yres, viafb_bpp1);
}
return 0;
@@ -872,7 +871,9 @@ static int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
if (info->flags & FBINFO_HWACCEL_DISABLED || info != viafbinfo)
return -ENODEV;
- if (chip_name == UNICHROME_CLE266 && viapar->iga_path == IGA2)
+ /* LCD ouput does not support hw cursors (at least on VN896) */
+ if ((chip_name == UNICHROME_CLE266 && viapar->iga_path == IGA2) ||
+ viafb_LCD_ON)
return -ENODEV;
viafb_show_hw_cursor(info, HW_Cursor_OFF);
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 9dd58804288..505be88c82a 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -266,7 +266,7 @@ static void __devexit virtballoon_remove(struct virtio_device *vdev)
static unsigned int features[] = { VIRTIO_BALLOON_F_MUST_TELL_HOST };
-static struct virtio_driver virtio_balloon = {
+static struct virtio_driver virtio_balloon_driver = {
.feature_table = features,
.feature_table_size = ARRAY_SIZE(features),
.driver.name = KBUILD_MODNAME,
@@ -279,12 +279,12 @@ static struct virtio_driver virtio_balloon = {
static int __init init(void)
{
- return register_virtio_driver(&virtio_balloon);
+ return register_virtio_driver(&virtio_balloon_driver);
}
static void __exit fini(void)
{
- unregister_virtio_driver(&virtio_balloon);
+ unregister_virtio_driver(&virtio_balloon_driver);
}
module_init(init);
module_exit(fini);
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index c8a3bec2683..4bdb7f1a907 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -29,8 +29,9 @@
* document number 313056-003, 313057-017: 82801H (ICH8)
* document number 316972-004, 316973-012: 82801I (ICH9)
* document number 319973-002, 319974-002: 82801J (ICH10)
- * document number 322169-001, 322170-001: 5 Series, 3400 Series (PCH)
+ * document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH)
* document number 320066-003, 320257-008: EP80597 (IICH)
+ * document number TBD : Cougar Point (CPT)
*/
/*
@@ -100,8 +101,22 @@ enum iTCO_chipsets {
TCO_ICH10DO, /* ICH10DO */
TCO_PCH, /* PCH Desktop Full Featured */
TCO_PCHM, /* PCH Mobile Full Featured */
+ TCO_P55, /* P55 */
+ TCO_PM55, /* PM55 */
+ TCO_H55, /* H55 */
+ TCO_QM57, /* QM57 */
+ TCO_H57, /* H57 */
+ TCO_HM55, /* HM55 */
+ TCO_Q57, /* Q57 */
+ TCO_HM57, /* HM57 */
TCO_PCHMSFF, /* PCH Mobile SFF Full Featured */
+ TCO_QS57, /* QS57 */
+ TCO_3400, /* 3400 */
+ TCO_3420, /* 3420 */
+ TCO_3450, /* 3450 */
TCO_EP80579, /* EP80579 */
+ TCO_CPTD, /* CPT Desktop */
+ TCO_CPTM, /* CPT Mobile */
};
static struct {
@@ -144,8 +159,22 @@ static struct {
{"ICH10DO", 2},
{"PCH Desktop Full Featured", 2},
{"PCH Mobile Full Featured", 2},
+ {"P55", 2},
+ {"PM55", 2},
+ {"H55", 2},
+ {"QM57", 2},
+ {"H57", 2},
+ {"HM55", 2},
+ {"Q57", 2},
+ {"HM57", 2},
{"PCH Mobile SFF Full Featured", 2},
+ {"QS57", 2},
+ {"3400", 2},
+ {"3420", 2},
+ {"3450", 2},
{"EP80579", 2},
+ {"CPT Desktop", 2},
+ {"CPT Mobile", 2},
{NULL, 0}
};
@@ -216,8 +245,22 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = {
{ ITCO_PCI_DEVICE(0x3a14, TCO_ICH10DO)},
{ ITCO_PCI_DEVICE(0x3b00, TCO_PCH)},
{ ITCO_PCI_DEVICE(0x3b01, TCO_PCHM)},
+ { ITCO_PCI_DEVICE(0x3b02, TCO_P55)},
+ { ITCO_PCI_DEVICE(0x3b03, TCO_PM55)},
+ { ITCO_PCI_DEVICE(0x3b06, TCO_H55)},
+ { ITCO_PCI_DEVICE(0x3b07, TCO_QM57)},
+ { ITCO_PCI_DEVICE(0x3b08, TCO_H57)},
+ { ITCO_PCI_DEVICE(0x3b09, TCO_HM55)},
+ { ITCO_PCI_DEVICE(0x3b0a, TCO_Q57)},
+ { ITCO_PCI_DEVICE(0x3b0b, TCO_HM57)},
{ ITCO_PCI_DEVICE(0x3b0d, TCO_PCHMSFF)},
+ { ITCO_PCI_DEVICE(0x3b0f, TCO_QS57)},
+ { ITCO_PCI_DEVICE(0x3b12, TCO_3400)},
+ { ITCO_PCI_DEVICE(0x3b14, TCO_3420)},
+ { ITCO_PCI_DEVICE(0x3b16, TCO_3450)},
{ ITCO_PCI_DEVICE(0x5031, TCO_EP80579)},
+ { ITCO_PCI_DEVICE(0x1c42, TCO_CPTD)},
+ { ITCO_PCI_DEVICE(0x1c43, TCO_CPTM)},
{ 0, }, /* End of list */
};
MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl);