linux/drivers/media/video/cx25840/cx25840-firmware.c
<<
>>
Prefs
   1/* cx25840 firmware functions
   2 *
   3 * This program is free software; you can redistribute it and/or
   4 * modify it under the terms of the GNU General Public License
   5 * as published by the Free Software Foundation; either version 2
   6 * of the License, or (at your option) any later version.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 *
  13 * You should have received a copy of the GNU General Public License
  14 * along with this program; if not, write to the Free Software
  15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  16 */
  17
  18#include <linux/module.h>
  19#include <linux/i2c.h>
  20#include <linux/firmware.h>
  21#include <media/v4l2-common.h>
  22#include <media/cx25840.h>
  23
  24#include "cx25840-core.h"
  25
  26/*
  27 * Mike Isely <isely@pobox.com> - The FWSEND parameter controls the
  28 * size of the firmware chunks sent down the I2C bus to the chip.
  29 * Previously this had been set to 1024 but unfortunately some I2C
  30 * implementations can't transfer data in such big gulps.
  31 * Specifically, the pvrusb2 driver has a hard limit of around 60
  32 * bytes, due to the encapsulation there of I2C traffic into USB
  33 * messages.  So we have to significantly reduce this parameter.
  34 */
  35#define FWSEND 48
  36
  37#define FWDEV(x) &((x)->dev)
  38
  39static char *firmware = "";
  40
  41module_param(firmware, charp, 0444);
  42
  43MODULE_PARM_DESC(firmware, "Firmware image to load");
  44
  45static void start_fw_load(struct i2c_client *client)
  46{
  47        /* DL_ADDR_LB=0 DL_ADDR_HB=0 */
  48        cx25840_write(client, 0x800, 0x00);
  49        cx25840_write(client, 0x801, 0x00);
  50        // DL_MAP=3 DL_AUTO_INC=0 DL_ENABLE=1
  51        cx25840_write(client, 0x803, 0x0b);
  52        /* AUTO_INC_DIS=1 */
  53        cx25840_write(client, 0x000, 0x20);
  54}
  55
  56static void end_fw_load(struct i2c_client *client)
  57{
  58        /* AUTO_INC_DIS=0 */
  59        cx25840_write(client, 0x000, 0x00);
  60        /* DL_ENABLE=0 */
  61        cx25840_write(client, 0x803, 0x03);
  62}
  63
  64static const char *get_fw_name(struct i2c_client *client)
  65{
  66        struct cx25840_state *state = to_state(i2c_get_clientdata(client));
  67
  68        if (firmware[0])
  69                return firmware;
  70        if (is_cx2388x(state))
  71                return "v4l-cx23885-avcore-01.fw";
  72        if (is_cx231xx(state))
  73                return "v4l-cx231xx-avcore-01.fw";
  74        return "v4l-cx25840.fw";
  75}
  76
  77static int check_fw_load(struct i2c_client *client, int size)
  78{
  79        /* DL_ADDR_HB DL_ADDR_LB */
  80        int s = cx25840_read(client, 0x801) << 8;
  81        s |= cx25840_read(client, 0x800);
  82
  83        if (size != s) {
  84                v4l_err(client, "firmware %s load failed\n",
  85                                get_fw_name(client));
  86                return -EINVAL;
  87        }
  88
  89        v4l_info(client, "loaded %s firmware (%d bytes)\n",
  90                        get_fw_name(client), size);
  91        return 0;
  92}
  93
  94static int fw_write(struct i2c_client *client, const u8 *data, int size)
  95{
  96        if (i2c_master_send(client, data, size) < size) {
  97                v4l_err(client, "firmware load i2c failure\n");
  98                return -ENOSYS;
  99        }
 100
 101        return 0;
 102}
 103
 104int cx25840_loadfw(struct i2c_client *client)
 105{
 106        struct cx25840_state *state = to_state(i2c_get_clientdata(client));
 107        const struct firmware *fw = NULL;
 108        u8 buffer[FWSEND];
 109        const u8 *ptr;
 110        const char *fwname = get_fw_name(client);
 111        int size, retval;
 112        int MAX_BUF_SIZE = FWSEND;
 113        u32 gpio_oe = 0, gpio_da = 0;
 114
 115        if (is_cx2388x(state)) {
 116                /* Preserve the GPIO OE and output bits */
 117                gpio_oe = cx25840_read(client, 0x160);
 118                gpio_da = cx25840_read(client, 0x164);
 119        }
 120
 121        if (is_cx231xx(state) && MAX_BUF_SIZE > 16) {
 122                v4l_err(client, " Firmware download size changed to 16 bytes max length\n");
 123                MAX_BUF_SIZE = 16;  /* cx231xx cannot accept more than 16 bytes at a time */
 124        }
 125
 126        if (request_firmware(&fw, fwname, FWDEV(client)) != 0) {
 127                v4l_err(client, "unable to open firmware %s\n", fwname);
 128                return -EINVAL;
 129        }
 130
 131        start_fw_load(client);
 132
 133        buffer[0] = 0x08;
 134        buffer[1] = 0x02;
 135
 136        size = fw->size;
 137        ptr = fw->data;
 138        while (size > 0) {
 139                int len = min(MAX_BUF_SIZE - 2, size);
 140
 141                memcpy(buffer + 2, ptr, len);
 142
 143                retval = fw_write(client, buffer, len + 2);
 144
 145                if (retval < 0) {
 146                        release_firmware(fw);
 147                        return retval;
 148                }
 149
 150                size -= len;
 151                ptr += len;
 152        }
 153
 154        end_fw_load(client);
 155
 156        size = fw->size;
 157        release_firmware(fw);
 158
 159        if (is_cx2388x(state)) {
 160                /* Restore GPIO configuration after f/w load */
 161                cx25840_write(client, 0x160, gpio_oe);
 162                cx25840_write(client, 0x164, gpio_da);
 163        }
 164
 165        return check_fw_load(client, size);
 166}
 167