Path: blob/master/drivers/media/video/cx23885/altera-ci.c
17726 views
/*1* altera-ci.c2*3* CI driver in conjunction with NetUp Dual DVB-T/C RF CI card4*5* Copyright (C) 2010,2011 NetUP Inc.6* Copyright (C) 2010,2011 Igor M. Liplianin <[email protected]>7*8* This program is free software; you can redistribute it and/or modify9* it under the terms of the GNU General Public License as published by10* the Free Software Foundation; either version 2 of the License, or11* (at your option) any later version.12*13* This program is distributed in the hope that it will be useful,14* but WITHOUT ANY WARRANTY; without even the implied warranty of15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the16*17* GNU General Public License for more details.18*19* You should have received a copy of the GNU General Public License20* along with this program; if not, write to the Free Software21* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.22*/2324/*25* currently cx23885 GPIO's used.26* GPIO-0 ~INT in27* GPIO-1 TMS out28* GPIO-2 ~reset chips out29* GPIO-3 to GPIO-10 data/addr for CA in/out30* GPIO-11 ~CS out31* GPIO-12 AD_RG out32* GPIO-13 ~WR out33* GPIO-14 ~RD out34* GPIO-15 ~RDY in35* GPIO-16 TCK out36* GPIO-17 TDO in37* GPIO-18 TDI out38*/39/*40* Bit definitions for MC417_RWD and MC417_OEN registers41* bits 31-1642* +-----------+43* | Reserved |44* +-----------+45* bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 846* +-------+-------+-------+-------+-------+-------+-------+-------+47* | TDI | TDO | TCK | RDY# | #RD | #WR | AD_RG | #CS |48* +-------+-------+-------+-------+-------+-------+-------+-------+49* bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 050* +-------+-------+-------+-------+-------+-------+-------+-------+51* | DATA7| DATA6| DATA5| DATA4| DATA3| DATA2| DATA1| DATA0|52* +-------+-------+-------+-------+-------+-------+-------+-------+53*/54#include <linux/version.h>55#include <media/videobuf-dma-sg.h>56#include <media/videobuf-dvb.h>57#include "altera-ci.h"58#include "dvb_ca_en50221.h"5960/* FPGA regs */61#define NETUP_CI_INT_CTRL 0x0062#define NETUP_CI_BUSCTRL2 0x0163#define NETUP_CI_ADDR0 0x0464#define NETUP_CI_ADDR1 0x0565#define NETUP_CI_DATA 0x0666#define NETUP_CI_BUSCTRL 0x0767#define NETUP_CI_PID_ADDR0 0x0868#define NETUP_CI_PID_ADDR1 0x0969#define NETUP_CI_PID_DATA 0x0a70#define NETUP_CI_TSA_DIV 0x0c71#define NETUP_CI_TSB_DIV 0x0d72#define NETUP_CI_REVISION 0x0f7374/* const for ci op */75#define NETUP_CI_FLG_CTL 176#define NETUP_CI_FLG_RD 177#define NETUP_CI_FLG_AD 17879static unsigned int ci_dbg;80module_param(ci_dbg, int, 0644);81MODULE_PARM_DESC(ci_dbg, "Enable CI debugging");8283static unsigned int pid_dbg;84module_param(pid_dbg, int, 0644);85MODULE_PARM_DESC(pid_dbg, "Enable PID filtering debugging");8687MODULE_DESCRIPTION("altera FPGA CI module");88MODULE_AUTHOR("Igor M. Liplianin <[email protected]>");89MODULE_LICENSE("GPL");9091#define ci_dbg_print(args...) \92do { \93if (ci_dbg) \94printk(KERN_DEBUG args); \95} while (0)9697#define pid_dbg_print(args...) \98do { \99if (pid_dbg) \100printk(KERN_DEBUG args); \101} while (0)102103struct altera_ci_state;104struct netup_hw_pid_filter;105106struct fpga_internal {107void *dev;108struct mutex fpga_mutex;/* two CI's on the same fpga */109struct netup_hw_pid_filter *pid_filt[2];110struct altera_ci_state *state[2];111struct work_struct work;112int (*fpga_rw) (void *dev, int flag, int data, int rw);113int cis_used;114int filts_used;115int strt_wrk;116};117118/* stores all private variables for communication with CI */119struct altera_ci_state {120struct fpga_internal *internal;121struct dvb_ca_en50221 ca;122int status;123int nr;124};125126/* stores all private variables for hardware pid filtering */127struct netup_hw_pid_filter {128struct fpga_internal *internal;129struct dvb_demux *demux;130/* save old functions */131int (*start_feed)(struct dvb_demux_feed *feed);132int (*stop_feed)(struct dvb_demux_feed *feed);133134int status;135int nr;136};137138/* internal params node */139struct fpga_inode {140/* pointer for internal params, one for each pair of CI's */141struct fpga_internal *internal;142struct fpga_inode *next_inode;143};144145/* first internal params */146static struct fpga_inode *fpga_first_inode;147148/* find chip by dev */149static struct fpga_inode *find_inode(void *dev)150{151struct fpga_inode *temp_chip = fpga_first_inode;152153if (temp_chip == NULL)154return temp_chip;155156/*157Search for the last fpga CI chip or158find it by dev */159while ((temp_chip != NULL) &&160(temp_chip->internal->dev != dev))161temp_chip = temp_chip->next_inode;162163return temp_chip;164}165/* check demux */166static struct fpga_internal *check_filter(struct fpga_internal *temp_int,167void *demux_dev, int filt_nr)168{169if (temp_int == NULL)170return NULL;171172if ((temp_int->pid_filt[filt_nr]) == NULL)173return NULL;174175if (temp_int->pid_filt[filt_nr]->demux == demux_dev)176return temp_int;177178return NULL;179}180181/* find chip by demux */182static struct fpga_inode *find_dinode(void *demux_dev)183{184struct fpga_inode *temp_chip = fpga_first_inode;185struct fpga_internal *temp_int;186187/*188* Search of the last fpga CI chip or189* find it by demux190*/191while (temp_chip != NULL) {192if (temp_chip->internal != NULL) {193temp_int = temp_chip->internal;194if (check_filter(temp_int, demux_dev, 0))195break;196if (check_filter(temp_int, demux_dev, 1))197break;198}199200temp_chip = temp_chip->next_inode;201}202203return temp_chip;204}205206/* deallocating chip */207static void remove_inode(struct fpga_internal *internal)208{209struct fpga_inode *prev_node = fpga_first_inode;210struct fpga_inode *del_node = find_inode(internal->dev);211212if (del_node != NULL) {213if (del_node == fpga_first_inode) {214fpga_first_inode = del_node->next_inode;215} else {216while (prev_node->next_inode != del_node)217prev_node = prev_node->next_inode;218219if (del_node->next_inode == NULL)220prev_node->next_inode = NULL;221else222prev_node->next_inode =223prev_node->next_inode->next_inode;224}225226kfree(del_node);227}228}229230/* allocating new chip */231static struct fpga_inode *append_internal(struct fpga_internal *internal)232{233struct fpga_inode *new_node = fpga_first_inode;234235if (new_node == NULL) {236new_node = kmalloc(sizeof(struct fpga_inode), GFP_KERNEL);237fpga_first_inode = new_node;238} else {239while (new_node->next_inode != NULL)240new_node = new_node->next_inode;241242new_node->next_inode =243kmalloc(sizeof(struct fpga_inode), GFP_KERNEL);244if (new_node->next_inode != NULL)245new_node = new_node->next_inode;246else247new_node = NULL;248}249250if (new_node != NULL) {251new_node->internal = internal;252new_node->next_inode = NULL;253}254255return new_node;256}257258static int netup_fpga_op_rw(struct fpga_internal *inter, int addr,259u8 val, u8 read)260{261inter->fpga_rw(inter->dev, NETUP_CI_FLG_AD, addr, 0);262return inter->fpga_rw(inter->dev, 0, val, read);263}264265/* flag - mem/io, read - read/write */266int altera_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot,267u8 flag, u8 read, int addr, u8 val)268{269270struct altera_ci_state *state = en50221->data;271struct fpga_internal *inter = state->internal;272273u8 store;274int mem = 0;275276if (0 != slot)277return -EINVAL;278279mutex_lock(&inter->fpga_mutex);280281netup_fpga_op_rw(inter, NETUP_CI_ADDR0, ((addr << 1) & 0xfe), 0);282netup_fpga_op_rw(inter, NETUP_CI_ADDR1, ((addr >> 7) & 0x7f), 0);283store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD);284285store &= 0x0f;286store |= ((state->nr << 7) | (flag << 6));287288netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, store, 0);289mem = netup_fpga_op_rw(inter, NETUP_CI_DATA, val, read);290291mutex_unlock(&inter->fpga_mutex);292293ci_dbg_print("%s: %s: addr=[0x%02x], %s=%x\n", __func__,294(read) ? "read" : "write", addr,295(flag == NETUP_CI_FLG_CTL) ? "ctl" : "mem",296(read) ? mem : val);297298return mem;299}300301int altera_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,302int slot, int addr)303{304return altera_ci_op_cam(en50221, slot, 0, NETUP_CI_FLG_RD, addr, 0);305}306307int altera_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,308int slot, int addr, u8 data)309{310return altera_ci_op_cam(en50221, slot, 0, 0, addr, data);311}312313int altera_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr)314{315return altera_ci_op_cam(en50221, slot, NETUP_CI_FLG_CTL,316NETUP_CI_FLG_RD, addr, 0);317}318319int altera_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot,320u8 addr, u8 data)321{322return altera_ci_op_cam(en50221, slot, NETUP_CI_FLG_CTL, 0, addr, data);323}324325int altera_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot)326{327struct altera_ci_state *state = en50221->data;328struct fpga_internal *inter = state->internal;329/* reasonable timeout for CI reset is 10 seconds */330unsigned long t_out = jiffies + msecs_to_jiffies(9999);331int ret;332333ci_dbg_print("%s\n", __func__);334335if (0 != slot)336return -EINVAL;337338mutex_lock(&inter->fpga_mutex);339340ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD);341netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL,342(ret & 0xcf) | (1 << (5 - state->nr)), 0);343344mutex_unlock(&inter->fpga_mutex);345346for (;;) {347mdelay(50);348349mutex_lock(&inter->fpga_mutex);350351ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL,3520, NETUP_CI_FLG_RD);353mutex_unlock(&inter->fpga_mutex);354355if ((ret & (1 << (5 - state->nr))) == 0)356break;357if (time_after(jiffies, t_out))358break;359}360361362ci_dbg_print("%s: %d msecs\n", __func__,363jiffies_to_msecs(jiffies + msecs_to_jiffies(9999) - t_out));364365return 0;366}367368int altera_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)369{370/* not implemented */371return 0;372}373374int altera_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot)375{376struct altera_ci_state *state = en50221->data;377struct fpga_internal *inter = state->internal;378int ret;379380ci_dbg_print("%s\n", __func__);381382if (0 != slot)383return -EINVAL;384385mutex_lock(&inter->fpga_mutex);386387ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD);388netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL,389(ret & 0x0f) | (1 << (3 - state->nr)), 0);390391mutex_unlock(&inter->fpga_mutex);392393return 0;394}395396/* work handler */397static void netup_read_ci_status(struct work_struct *work)398{399struct fpga_internal *inter =400container_of(work, struct fpga_internal, work);401int ret;402403ci_dbg_print("%s\n", __func__);404405mutex_lock(&inter->fpga_mutex);406/* ack' irq */407ret = netup_fpga_op_rw(inter, NETUP_CI_INT_CTRL, 0, NETUP_CI_FLG_RD);408ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD);409410mutex_unlock(&inter->fpga_mutex);411412if (inter->state[1] != NULL) {413inter->state[1]->status =414((ret & 1) == 0 ?415DVB_CA_EN50221_POLL_CAM_PRESENT |416DVB_CA_EN50221_POLL_CAM_READY : 0);417ci_dbg_print("%s: setting CI[1] status = 0x%x\n",418__func__, inter->state[1]->status);419};420421if (inter->state[0] != NULL) {422inter->state[0]->status =423((ret & 2) == 0 ?424DVB_CA_EN50221_POLL_CAM_PRESENT |425DVB_CA_EN50221_POLL_CAM_READY : 0);426ci_dbg_print("%s: setting CI[0] status = 0x%x\n",427__func__, inter->state[0]->status);428};429}430431/* CI irq handler */432int altera_ci_irq(void *dev)433{434struct fpga_inode *temp_int = NULL;435struct fpga_internal *inter = NULL;436437ci_dbg_print("%s\n", __func__);438439if (dev != NULL) {440temp_int = find_inode(dev);441if (temp_int != NULL) {442inter = temp_int->internal;443schedule_work(&inter->work);444}445}446447return 1;448}449EXPORT_SYMBOL(altera_ci_irq);450451int altera_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot,452int open)453{454struct altera_ci_state *state = en50221->data;455456if (0 != slot)457return -EINVAL;458459return state->status;460}461462void altera_hw_filt_release(void *main_dev, int filt_nr)463{464struct fpga_inode *temp_int = find_inode(main_dev);465struct netup_hw_pid_filter *pid_filt = NULL;466467ci_dbg_print("%s\n", __func__);468469if (temp_int != NULL) {470pid_filt = temp_int->internal->pid_filt[filt_nr - 1];471/* stored old feed controls */472pid_filt->demux->start_feed = pid_filt->start_feed;473pid_filt->demux->stop_feed = pid_filt->stop_feed;474475if (((--(temp_int->internal->filts_used)) <= 0) &&476((temp_int->internal->cis_used) <= 0)) {477478ci_dbg_print("%s: Actually removing\n", __func__);479480remove_inode(temp_int->internal);481kfree(pid_filt->internal);482}483484kfree(pid_filt);485486}487488}489EXPORT_SYMBOL(altera_hw_filt_release);490491void altera_ci_release(void *dev, int ci_nr)492{493struct fpga_inode *temp_int = find_inode(dev);494struct altera_ci_state *state = NULL;495496ci_dbg_print("%s\n", __func__);497498if (temp_int != NULL) {499state = temp_int->internal->state[ci_nr - 1];500altera_hw_filt_release(dev, ci_nr);501502503if (((temp_int->internal->filts_used) <= 0) &&504((--(temp_int->internal->cis_used)) <= 0)) {505506ci_dbg_print("%s: Actually removing\n", __func__);507508remove_inode(temp_int->internal);509kfree(state->internal);510}511512if (state != NULL) {513if (state->ca.data != NULL)514dvb_ca_en50221_release(&state->ca);515516kfree(state);517}518}519520}521EXPORT_SYMBOL(altera_ci_release);522523static void altera_pid_control(struct netup_hw_pid_filter *pid_filt,524u16 pid, int onoff)525{526struct fpga_internal *inter = pid_filt->internal;527u8 store = 0;528529/* pid 0-0x1f always enabled, don't touch them */530if ((pid == 0x2000) || (pid < 0x20))531return;532533mutex_lock(&inter->fpga_mutex);534535netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR0, (pid >> 3) & 0xff, 0);536netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR1,537((pid >> 11) & 0x03) | (pid_filt->nr << 2), 0);538539store = netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, 0, NETUP_CI_FLG_RD);540541if (onoff)/* 0 - on, 1 - off */542store |= (1 << (pid & 7));543else544store &= ~(1 << (pid & 7));545546netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, store, 0);547548mutex_unlock(&inter->fpga_mutex);549550pid_dbg_print("%s: (%d) set pid: %5d 0x%04x '%s'\n", __func__,551pid_filt->nr, pid, pid, onoff ? "off" : "on");552}553554static void altera_toggle_fullts_streaming(struct netup_hw_pid_filter *pid_filt,555int filt_nr, int onoff)556{557struct fpga_internal *inter = pid_filt->internal;558u8 store = 0;559int i;560561pid_dbg_print("%s: pid_filt->nr[%d] now %s\n", __func__, pid_filt->nr,562onoff ? "off" : "on");563564if (onoff)/* 0 - on, 1 - off */565store = 0xff;/* ignore pid */566else567store = 0;/* enable pid */568569mutex_lock(&inter->fpga_mutex);570571for (i = 0; i < 1024; i++) {572netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR0, i & 0xff, 0);573574netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR1,575((i >> 8) & 0x03) | (pid_filt->nr << 2), 0);576/* pid 0-0x1f always enabled */577netup_fpga_op_rw(inter, NETUP_CI_PID_DATA,578(i > 3 ? store : 0), 0);579}580581mutex_unlock(&inter->fpga_mutex);582}583584int altera_pid_feed_control(void *demux_dev, int filt_nr,585struct dvb_demux_feed *feed, int onoff)586{587struct fpga_inode *temp_int = find_dinode(demux_dev);588struct fpga_internal *inter = temp_int->internal;589struct netup_hw_pid_filter *pid_filt = inter->pid_filt[filt_nr - 1];590591altera_pid_control(pid_filt, feed->pid, onoff ? 0 : 1);592/* call old feed proc's */593if (onoff)594pid_filt->start_feed(feed);595else596pid_filt->stop_feed(feed);597598if (feed->pid == 0x2000)599altera_toggle_fullts_streaming(pid_filt, filt_nr,600onoff ? 0 : 1);601602return 0;603}604EXPORT_SYMBOL(altera_pid_feed_control);605606int altera_ci_start_feed(struct dvb_demux_feed *feed, int num)607{608altera_pid_feed_control(feed->demux, num, feed, 1);609610return 0;611}612613int altera_ci_stop_feed(struct dvb_demux_feed *feed, int num)614{615altera_pid_feed_control(feed->demux, num, feed, 0);616617return 0;618}619620int altera_ci_start_feed_1(struct dvb_demux_feed *feed)621{622return altera_ci_start_feed(feed, 1);623}624625int altera_ci_stop_feed_1(struct dvb_demux_feed *feed)626{627return altera_ci_stop_feed(feed, 1);628}629630int altera_ci_start_feed_2(struct dvb_demux_feed *feed)631{632return altera_ci_start_feed(feed, 2);633}634635int altera_ci_stop_feed_2(struct dvb_demux_feed *feed)636{637return altera_ci_stop_feed(feed, 2);638}639640int altera_hw_filt_init(struct altera_ci_config *config, int hw_filt_nr)641{642struct netup_hw_pid_filter *pid_filt = NULL;643struct fpga_inode *temp_int = find_inode(config->dev);644struct fpga_internal *inter = NULL;645int ret = 0;646647pid_filt = kzalloc(sizeof(struct netup_hw_pid_filter), GFP_KERNEL);648649ci_dbg_print("%s\n", __func__);650651if (!pid_filt) {652ret = -ENOMEM;653goto err;654}655656if (temp_int != NULL) {657inter = temp_int->internal;658(inter->filts_used)++;659ci_dbg_print("%s: Find Internal Structure!\n", __func__);660} else {661inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL);662if (!inter) {663ret = -ENOMEM;664goto err;665}666667temp_int = append_internal(inter);668inter->filts_used = 1;669inter->dev = config->dev;670inter->fpga_rw = config->fpga_rw;671mutex_init(&inter->fpga_mutex);672inter->strt_wrk = 1;673ci_dbg_print("%s: Create New Internal Structure!\n", __func__);674}675676ci_dbg_print("%s: setting hw pid filter = %p for ci = %d\n", __func__,677pid_filt, hw_filt_nr - 1);678inter->pid_filt[hw_filt_nr - 1] = pid_filt;679pid_filt->demux = config->demux;680pid_filt->internal = inter;681pid_filt->nr = hw_filt_nr - 1;682/* store old feed controls */683pid_filt->start_feed = config->demux->start_feed;684pid_filt->stop_feed = config->demux->stop_feed;685/* replace with new feed controls */686if (hw_filt_nr == 1) {687pid_filt->demux->start_feed = altera_ci_start_feed_1;688pid_filt->demux->stop_feed = altera_ci_stop_feed_1;689} else if (hw_filt_nr == 2) {690pid_filt->demux->start_feed = altera_ci_start_feed_2;691pid_filt->demux->stop_feed = altera_ci_stop_feed_2;692}693694altera_toggle_fullts_streaming(pid_filt, 0, 1);695696return 0;697err:698ci_dbg_print("%s: Can't init hardware filter: Error %d\n",699__func__, ret);700701kfree(pid_filt);702703return ret;704}705EXPORT_SYMBOL(altera_hw_filt_init);706707int altera_ci_init(struct altera_ci_config *config, int ci_nr)708{709struct altera_ci_state *state;710struct fpga_inode *temp_int = find_inode(config->dev);711struct fpga_internal *inter = NULL;712int ret = 0;713u8 store = 0;714715state = kzalloc(sizeof(struct altera_ci_state), GFP_KERNEL);716717ci_dbg_print("%s\n", __func__);718719if (!state) {720ret = -ENOMEM;721goto err;722}723724if (temp_int != NULL) {725inter = temp_int->internal;726(inter->cis_used)++;727ci_dbg_print("%s: Find Internal Structure!\n", __func__);728} else {729inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL);730if (!inter) {731ret = -ENOMEM;732goto err;733}734735temp_int = append_internal(inter);736inter->cis_used = 1;737inter->dev = config->dev;738inter->fpga_rw = config->fpga_rw;739mutex_init(&inter->fpga_mutex);740inter->strt_wrk = 1;741ci_dbg_print("%s: Create New Internal Structure!\n", __func__);742}743744ci_dbg_print("%s: setting state = %p for ci = %d\n", __func__,745state, ci_nr - 1);746inter->state[ci_nr - 1] = state;747state->internal = inter;748state->nr = ci_nr - 1;749750state->ca.owner = THIS_MODULE;751state->ca.read_attribute_mem = altera_ci_read_attribute_mem;752state->ca.write_attribute_mem = altera_ci_write_attribute_mem;753state->ca.read_cam_control = altera_ci_read_cam_ctl;754state->ca.write_cam_control = altera_ci_write_cam_ctl;755state->ca.slot_reset = altera_ci_slot_reset;756state->ca.slot_shutdown = altera_ci_slot_shutdown;757state->ca.slot_ts_enable = altera_ci_slot_ts_ctl;758state->ca.poll_slot_status = altera_poll_ci_slot_status;759state->ca.data = state;760761ret = dvb_ca_en50221_init(config->adapter,762&state->ca,763/* flags */ 0,764/* n_slots */ 1);765if (0 != ret)766goto err;767768altera_hw_filt_init(config, ci_nr);769770if (inter->strt_wrk) {771INIT_WORK(&inter->work, netup_read_ci_status);772inter->strt_wrk = 0;773}774775ci_dbg_print("%s: CI initialized!\n", __func__);776777mutex_lock(&inter->fpga_mutex);778779/* Enable div */780netup_fpga_op_rw(inter, NETUP_CI_TSA_DIV, 0x0, 0);781netup_fpga_op_rw(inter, NETUP_CI_TSB_DIV, 0x0, 0);782783/* enable TS out */784store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, 0, NETUP_CI_FLG_RD);785store |= (3 << 4);786netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0);787788ret = netup_fpga_op_rw(inter, NETUP_CI_REVISION, 0, NETUP_CI_FLG_RD);789/* enable irq */790netup_fpga_op_rw(inter, NETUP_CI_INT_CTRL, 0x44, 0);791792mutex_unlock(&inter->fpga_mutex);793794ci_dbg_print("%s: NetUP CI Revision = 0x%x\n", __func__, ret);795796schedule_work(&inter->work);797798return 0;799err:800ci_dbg_print("%s: Cannot initialize CI: Error %d.\n", __func__, ret);801802kfree(state);803804return ret;805}806EXPORT_SYMBOL(altera_ci_init);807808int altera_ci_tuner_reset(void *dev, int ci_nr)809{810struct fpga_inode *temp_int = find_inode(dev);811struct fpga_internal *inter = NULL;812u8 store;813814ci_dbg_print("%s\n", __func__);815816if (temp_int == NULL)817return -1;818819if (temp_int->internal == NULL)820return -1;821822inter = temp_int->internal;823824mutex_lock(&inter->fpga_mutex);825826store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, 0, NETUP_CI_FLG_RD);827store &= ~(4 << (2 - ci_nr));828netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0);829msleep(100);830store |= (4 << (2 - ci_nr));831netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0);832833mutex_unlock(&inter->fpga_mutex);834835return 0;836}837EXPORT_SYMBOL(altera_ci_tuner_reset);838839840