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