1*b285192aSMauro Carvalho Chehab /* 2*b285192aSMauro Carvalho Chehab * Driver for Silicon Labs C8051F300 microcontroller. 3*b285192aSMauro Carvalho Chehab * 4*b285192aSMauro Carvalho Chehab * It is used for LNB power control in TeVii S470, 5*b285192aSMauro Carvalho Chehab * TBS 6920 PCIe DVB-S2 cards. 6*b285192aSMauro Carvalho Chehab * 7*b285192aSMauro Carvalho Chehab * Microcontroller connected to cx23885 GPIO pins: 8*b285192aSMauro Carvalho Chehab * GPIO0 - data - P0.3 F300 9*b285192aSMauro Carvalho Chehab * GPIO1 - reset - P0.2 F300 10*b285192aSMauro Carvalho Chehab * GPIO2 - clk - P0.1 F300 11*b285192aSMauro Carvalho Chehab * GPIO3 - busy - P0.0 F300 12*b285192aSMauro Carvalho Chehab * 13*b285192aSMauro Carvalho Chehab * Copyright (C) 2009 Igor M. Liplianin <liplianin@me.by> 14*b285192aSMauro Carvalho Chehab * 15*b285192aSMauro Carvalho Chehab * This program is free software; you can redistribute it and/or modify 16*b285192aSMauro Carvalho Chehab * it under the terms of the GNU General Public License as published by 17*b285192aSMauro Carvalho Chehab * the Free Software Foundation; either version 2 of the License, or 18*b285192aSMauro Carvalho Chehab * (at your option) any later version. 19*b285192aSMauro Carvalho Chehab * 20*b285192aSMauro Carvalho Chehab * This program is distributed in the hope that it will be useful, 21*b285192aSMauro Carvalho Chehab * but WITHOUT ANY WARRANTY; without even the implied warranty of 22*b285192aSMauro Carvalho Chehab * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23*b285192aSMauro Carvalho Chehab * 24*b285192aSMauro Carvalho Chehab * GNU General Public License for more details. 25*b285192aSMauro Carvalho Chehab * 26*b285192aSMauro Carvalho Chehab * You should have received a copy of the GNU General Public License 27*b285192aSMauro Carvalho Chehab * along with this program; if not, write to the Free Software 28*b285192aSMauro Carvalho Chehab * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 29*b285192aSMauro Carvalho Chehab */ 30*b285192aSMauro Carvalho Chehab 31*b285192aSMauro Carvalho Chehab #include "cx23885.h" 32*b285192aSMauro Carvalho Chehab 33*b285192aSMauro Carvalho Chehab #define F300_DATA GPIO_0 34*b285192aSMauro Carvalho Chehab #define F300_RESET GPIO_1 35*b285192aSMauro Carvalho Chehab #define F300_CLK GPIO_2 36*b285192aSMauro Carvalho Chehab #define F300_BUSY GPIO_3 37*b285192aSMauro Carvalho Chehab 38*b285192aSMauro Carvalho Chehab static void f300_set_line(struct cx23885_dev *dev, u32 line, u8 lvl) 39*b285192aSMauro Carvalho Chehab { 40*b285192aSMauro Carvalho Chehab cx23885_gpio_enable(dev, line, 1); 41*b285192aSMauro Carvalho Chehab if (lvl == 1) 42*b285192aSMauro Carvalho Chehab cx23885_gpio_set(dev, line); 43*b285192aSMauro Carvalho Chehab else 44*b285192aSMauro Carvalho Chehab cx23885_gpio_clear(dev, line); 45*b285192aSMauro Carvalho Chehab } 46*b285192aSMauro Carvalho Chehab 47*b285192aSMauro Carvalho Chehab static u8 f300_get_line(struct cx23885_dev *dev, u32 line) 48*b285192aSMauro Carvalho Chehab { 49*b285192aSMauro Carvalho Chehab cx23885_gpio_enable(dev, line, 0); 50*b285192aSMauro Carvalho Chehab 51*b285192aSMauro Carvalho Chehab return cx23885_gpio_get(dev, line); 52*b285192aSMauro Carvalho Chehab } 53*b285192aSMauro Carvalho Chehab 54*b285192aSMauro Carvalho Chehab static void f300_send_byte(struct cx23885_dev *dev, u8 dta) 55*b285192aSMauro Carvalho Chehab { 56*b285192aSMauro Carvalho Chehab u8 i; 57*b285192aSMauro Carvalho Chehab 58*b285192aSMauro Carvalho Chehab for (i = 0; i < 8; i++) { 59*b285192aSMauro Carvalho Chehab f300_set_line(dev, F300_CLK, 0); 60*b285192aSMauro Carvalho Chehab udelay(30); 61*b285192aSMauro Carvalho Chehab f300_set_line(dev, F300_DATA, (dta & 0x80) >> 7);/* msb first */ 62*b285192aSMauro Carvalho Chehab udelay(30); 63*b285192aSMauro Carvalho Chehab dta <<= 1; 64*b285192aSMauro Carvalho Chehab f300_set_line(dev, F300_CLK, 1); 65*b285192aSMauro Carvalho Chehab udelay(30); 66*b285192aSMauro Carvalho Chehab } 67*b285192aSMauro Carvalho Chehab } 68*b285192aSMauro Carvalho Chehab 69*b285192aSMauro Carvalho Chehab static u8 f300_get_byte(struct cx23885_dev *dev) 70*b285192aSMauro Carvalho Chehab { 71*b285192aSMauro Carvalho Chehab u8 i, dta = 0; 72*b285192aSMauro Carvalho Chehab 73*b285192aSMauro Carvalho Chehab for (i = 0; i < 8; i++) { 74*b285192aSMauro Carvalho Chehab f300_set_line(dev, F300_CLK, 0); 75*b285192aSMauro Carvalho Chehab udelay(30); 76*b285192aSMauro Carvalho Chehab dta <<= 1; 77*b285192aSMauro Carvalho Chehab f300_set_line(dev, F300_CLK, 1); 78*b285192aSMauro Carvalho Chehab udelay(30); 79*b285192aSMauro Carvalho Chehab dta |= f300_get_line(dev, F300_DATA);/* msb first */ 80*b285192aSMauro Carvalho Chehab 81*b285192aSMauro Carvalho Chehab } 82*b285192aSMauro Carvalho Chehab 83*b285192aSMauro Carvalho Chehab return dta; 84*b285192aSMauro Carvalho Chehab } 85*b285192aSMauro Carvalho Chehab 86*b285192aSMauro Carvalho Chehab static u8 f300_xfer(struct dvb_frontend *fe, u8 *buf) 87*b285192aSMauro Carvalho Chehab { 88*b285192aSMauro Carvalho Chehab struct cx23885_tsport *port = fe->dvb->priv; 89*b285192aSMauro Carvalho Chehab struct cx23885_dev *dev = port->dev; 90*b285192aSMauro Carvalho Chehab u8 i, temp, ret = 0; 91*b285192aSMauro Carvalho Chehab 92*b285192aSMauro Carvalho Chehab temp = buf[0]; 93*b285192aSMauro Carvalho Chehab for (i = 0; i < buf[0]; i++) 94*b285192aSMauro Carvalho Chehab temp += buf[i + 1]; 95*b285192aSMauro Carvalho Chehab temp = (~temp + 1);/* get check sum */ 96*b285192aSMauro Carvalho Chehab buf[1 + buf[0]] = temp; 97*b285192aSMauro Carvalho Chehab 98*b285192aSMauro Carvalho Chehab f300_set_line(dev, F300_RESET, 1); 99*b285192aSMauro Carvalho Chehab f300_set_line(dev, F300_CLK, 1); 100*b285192aSMauro Carvalho Chehab udelay(30); 101*b285192aSMauro Carvalho Chehab f300_set_line(dev, F300_DATA, 1); 102*b285192aSMauro Carvalho Chehab msleep(1); 103*b285192aSMauro Carvalho Chehab 104*b285192aSMauro Carvalho Chehab /* question: */ 105*b285192aSMauro Carvalho Chehab f300_set_line(dev, F300_RESET, 0);/* begin to send data */ 106*b285192aSMauro Carvalho Chehab msleep(1); 107*b285192aSMauro Carvalho Chehab 108*b285192aSMauro Carvalho Chehab f300_send_byte(dev, 0xe0);/* the slave address is 0xe0, write */ 109*b285192aSMauro Carvalho Chehab msleep(1); 110*b285192aSMauro Carvalho Chehab 111*b285192aSMauro Carvalho Chehab temp = buf[0]; 112*b285192aSMauro Carvalho Chehab temp += 2; 113*b285192aSMauro Carvalho Chehab for (i = 0; i < temp; i++) 114*b285192aSMauro Carvalho Chehab f300_send_byte(dev, buf[i]); 115*b285192aSMauro Carvalho Chehab 116*b285192aSMauro Carvalho Chehab f300_set_line(dev, F300_RESET, 1);/* sent data over */ 117*b285192aSMauro Carvalho Chehab f300_set_line(dev, F300_DATA, 1); 118*b285192aSMauro Carvalho Chehab 119*b285192aSMauro Carvalho Chehab /* answer: */ 120*b285192aSMauro Carvalho Chehab temp = 0; 121*b285192aSMauro Carvalho Chehab for (i = 0; ((i < 8) & (temp == 0)); i++) { 122*b285192aSMauro Carvalho Chehab msleep(1); 123*b285192aSMauro Carvalho Chehab if (f300_get_line(dev, F300_BUSY) == 0) 124*b285192aSMauro Carvalho Chehab temp = 1; 125*b285192aSMauro Carvalho Chehab } 126*b285192aSMauro Carvalho Chehab 127*b285192aSMauro Carvalho Chehab if (i > 7) { 128*b285192aSMauro Carvalho Chehab printk(KERN_ERR "%s: timeout, the slave no response\n", 129*b285192aSMauro Carvalho Chehab __func__); 130*b285192aSMauro Carvalho Chehab ret = 1; /* timeout, the slave no response */ 131*b285192aSMauro Carvalho Chehab } else { /* the slave not busy, prepare for getting data */ 132*b285192aSMauro Carvalho Chehab f300_set_line(dev, F300_RESET, 0);/*ready...*/ 133*b285192aSMauro Carvalho Chehab msleep(1); 134*b285192aSMauro Carvalho Chehab f300_send_byte(dev, 0xe1);/* 0xe1 is Read */ 135*b285192aSMauro Carvalho Chehab msleep(1); 136*b285192aSMauro Carvalho Chehab temp = f300_get_byte(dev);/*get the data length */ 137*b285192aSMauro Carvalho Chehab if (temp > 14) 138*b285192aSMauro Carvalho Chehab temp = 14; 139*b285192aSMauro Carvalho Chehab 140*b285192aSMauro Carvalho Chehab for (i = 0; i < (temp + 1); i++) 141*b285192aSMauro Carvalho Chehab f300_get_byte(dev);/* get data to empty buffer */ 142*b285192aSMauro Carvalho Chehab 143*b285192aSMauro Carvalho Chehab f300_set_line(dev, F300_RESET, 1);/* received data over */ 144*b285192aSMauro Carvalho Chehab f300_set_line(dev, F300_DATA, 1); 145*b285192aSMauro Carvalho Chehab } 146*b285192aSMauro Carvalho Chehab 147*b285192aSMauro Carvalho Chehab return ret; 148*b285192aSMauro Carvalho Chehab } 149*b285192aSMauro Carvalho Chehab 150*b285192aSMauro Carvalho Chehab int f300_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) 151*b285192aSMauro Carvalho Chehab { 152*b285192aSMauro Carvalho Chehab u8 buf[16]; 153*b285192aSMauro Carvalho Chehab 154*b285192aSMauro Carvalho Chehab buf[0] = 0x05; 155*b285192aSMauro Carvalho Chehab buf[1] = 0x38;/* write port */ 156*b285192aSMauro Carvalho Chehab buf[2] = 0x01;/* A port, lnb power */ 157*b285192aSMauro Carvalho Chehab 158*b285192aSMauro Carvalho Chehab switch (voltage) { 159*b285192aSMauro Carvalho Chehab case SEC_VOLTAGE_13: 160*b285192aSMauro Carvalho Chehab buf[3] = 0x01;/* power on */ 161*b285192aSMauro Carvalho Chehab buf[4] = 0x02;/* B port, H/V */ 162*b285192aSMauro Carvalho Chehab buf[5] = 0x00;/*13V v*/ 163*b285192aSMauro Carvalho Chehab break; 164*b285192aSMauro Carvalho Chehab case SEC_VOLTAGE_18: 165*b285192aSMauro Carvalho Chehab buf[3] = 0x01; 166*b285192aSMauro Carvalho Chehab buf[4] = 0x02; 167*b285192aSMauro Carvalho Chehab buf[5] = 0x01;/* 18V h*/ 168*b285192aSMauro Carvalho Chehab break; 169*b285192aSMauro Carvalho Chehab case SEC_VOLTAGE_OFF: 170*b285192aSMauro Carvalho Chehab buf[3] = 0x00;/* power off */ 171*b285192aSMauro Carvalho Chehab buf[4] = 0x00; 172*b285192aSMauro Carvalho Chehab buf[5] = 0x00; 173*b285192aSMauro Carvalho Chehab break; 174*b285192aSMauro Carvalho Chehab } 175*b285192aSMauro Carvalho Chehab 176*b285192aSMauro Carvalho Chehab return f300_xfer(fe, buf); 177*b285192aSMauro Carvalho Chehab } 178