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