/*
* SMI PCIe driver for DVBSky cards.
*
* Copyright (C) 2014 Max nibble <nibble.max@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.
*/
#include "smipcie.h"
#include "m88ds3103.h"
#include "m88ts2022.h"
#include "m88rs6000t.h"
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
static int smi_hw_init(struct smi_dev *dev)
{
u32 port_mux, port_ctrl, int_stat;
/* set port mux.*/
port_mux = smi_read(MUX_MODE_CTRL);
port_mux &= ~(rbPaMSMask);
port_mux |= rbPaMSDtvNoGpio;
port_mux &= ~(rbPbMSMask);
port_mux |= rbPbMSDtvNoGpio;
port_mux &= ~(0x0f0000);
port_mux |= 0x50000;
smi_write(MUX_MODE_CTRL, port_mux);
/* set DTV register.*/
/* Port A */
port_ctrl = smi_read(VIDEO_CTRL_STATUS_A);
port_ctrl &= ~0x01;
smi_write(VIDEO_CTRL_STATUS_A, port_ctrl);
port_ctrl = smi_read(MPEG2_CTRL_A);
port_ctrl &= ~0x40;
port_ctrl |= 0x80;
smi_write(MPEG2_CTRL_A, port_ctrl);
/* Port B */
port_ctrl = smi_read(VIDEO_CTRL_STATUS_B);
port_ctrl &= ~0x01;
smi_write(VIDEO_CTRL_STATUS_B, port_ctrl);
port_ctrl = smi_read(MPEG2_CTRL_B);
port_ctrl &= ~0x40;
port_ctrl |= 0x80;
smi_write(MPEG2_CTRL_B, port_ctrl);
/* disable and clear interrupt.*/
smi_write(MSI_INT_ENA_CLR, ALL_INT);
int_stat = smi_read(MSI_INT_STATUS);
smi_write(MSI_INT_STATUS_CLR, int_stat);
/* reset demod.*/
smi_clear(PERIPHERAL_CTRL, 0x0303);
msleep(50);
smi_set(PERIPHERAL_CTRL, 0x0101);
return 0;
}
/* i2c bit bus.*/
static void smi_i2c_cfg(struct smi_dev *dev, u32 sw_ctl)
{
u32 dwCtrl;
dwCtrl = smi_read(sw_ctl);
dwCtrl &= ~0x18; /* disable output.*/
dwCtrl |= 0x21; /* reset and software mode.*/
dwCtrl &= ~0xff00;
dwCtrl |= 0x6400;
smi_write(sw_ctl, dwCtrl);
msleep(20);
dwCtrl = smi_read(sw_ctl);
dwCtrl &= ~0x20;
smi_write(sw_ctl, dwCtrl);
}
static void smi_i2c_setsda(struct smi_dev *dev, int state, u32 sw_ctl)
{
if (state) {
/* set as input.*/
smi_clear(sw_ctl, SW_I2C_MSK_DAT_EN);
} else {
smi_clear(sw_ctl, SW_I2C_MSK_DAT_OUT);
/* set as output.*/
smi_set(sw_ctl, SW_I2C_MSK_DAT_EN);
}
}
static void smi_i2c_setscl(void *data, int state, u32 sw_ctl)
{
struct smi_dev *dev = data;
if (state) {
/* set as input.*/
smi_clear(sw_ctl, SW_I2C_MSK_CLK_EN);
} else {
smi_clear(sw_ctl, SW_I2C_MSK_CLK_OUT);
/* set as output.*/
smi_set(sw_ctl, SW_I2C_MSK_CLK_EN);
}
}
static int smi_i2c_getsda(void *data, u32 sw_ctl)
{
struct smi_dev *dev = data;
/* set as input.*/
smi_clear(sw_ctl, SW_I2C_MSK_DAT_EN);
udelay(1);
return (smi_read(sw_ctl) & SW_I2C_MSK_DAT_IN) ? 1 : 0;
}
static int smi_i2c_getscl(void *data, u32 sw_ctl)
{
struct smi_dev *dev = data;
/* set as input.*/
smi_clear(sw_ctl, SW_I2C_MSK_CLK_EN);
udelay(1);
return (smi_read(sw_ctl) & SW_I2C_MSK_CLK_IN) ? 1 : 0;
}
/* i2c 0.*/
static void smi_i2c0_setsda(void *data, int state)
{
struct smi_dev *dev = data;
smi_i2c_setsda(dev, state, I2C_A_SW_CTL);
}
static void smi_i2c0_setscl(void *data, int state)
{
struct smi_dev *dev = data;
smi_i2c_setscl(dev, state, I2C_A_SW_CTL);
}
static int smi_i2c0_getsda(void *data)
{
struct smi_dev *dev =<