linux/drivers/media/i2c/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/drv-intf/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
  64#define CX2388x_FIRMWARE "v4l-cx23885-avcore-01.fw"
  65#define CX231xx_FIRMWARE "v4l-cx231xx-avcore-01.fw"
  66#define CX25840_FIRMWARE "v4l-cx25840.fw"
  67
  68static const char *get_fw_name(struct i2c_client *client)
  69{
  70        struct cx25840_state *state = to_state(i2c_get_clientdata(client));
  71
  72        if (firmware[0])
  73                return firmware;
  74        if (is_cx2388x(state))
  75                return CX2388x_FIRMWARE;
  76        if (is_cx231xx(state))
  77                return CX231xx_FIRMWARE;
  78        return CX25840_FIRMWARE;
  79}
  80
  81static int check_fw_load(struct i2c_client *client, int size)
  82{
  83        /* DL_ADDR_HB DL_ADDR_LB */
  84        int s = cx25840_read(client, 0x801) << 8;
  85        s |= cx25840_read(client, 0x800);
  86
  87        if (size != s) {
  88                v4l_err(client, "firmware %s load failed\n",
  89                                get_fw_name(client));
  90                return -EINVAL;
  91        }
  92
  93        v4l_info(client, "loaded %s firmware (%d bytes)\n",
  94                        get_fw_name(client), size);
  95        return 0;
  96}
  97
  98static int fw_write(struct i2c_client *client, const u8 *data, int size)
  99{
 100        if (i2c_master_send(client, data, size) < size) {
 101                v4l_err(client, "firmware load i2c failure\n");
 102                return -ENOSYS;
 103        }
 104
 105        return 0;
 106}
 107
 108int cx25840_loadfw(struct i2c_client *client)
 109{
 110        struct cx25840_state *state = to_state(i2c_get_clientdata(client));
 111        const struct firmware *fw = NULL;
 112        u8 buffer[FWSEND];
 113        const u8 *ptr;
 114        const char *fwname = get_fw_name(client);
 115        int size, retval;
 116        int max_buf_size = FWSEND;
 117        u32 gpio_oe = 0, gpio_da = 0;
 118
 119        if (is_cx2388x(state)) {
 120                /* Preserve the GPIO OE and output bits */
 121                gpio_oe = cx25840_read(client, 0x160);
 122                gpio_da = cx25840_read(client, 0x164);
 123        }
 124
 125        /* cx231xx cannot accept more than 16 bytes at a time */
 126        if (is_cx231xx(state) && max_buf_size > 16)
 127                max_buf_size = 16;
 128
 129        if (request_firmware(&fw, fwname, FWDEV(client)) != 0) {
 130                v4l_err(client, "unable to open firmware %s\n", fwname);
 131                return -EINVAL;
 132        }
 133
 134        start_fw_load(client);
 135
 136        buffer[0] = 0x08;
 137        buffer[1] = 0x02;
 138
 139        size = fw->size;
 140        ptr = fw->data;
 141        while (size > 0) {
 142                int len = min(max_buf_size - 2, size);
 143
 144                memcpy(buffer + 2, ptr, len);
 145
 146                retval = fw_write(client, buffer, len + 2);
 147
 148                if (retval < 0) {
 149                        release_firmware(fw);
 150                        return retval;
 151                }
 152
 153                size -= len;
 154                ptr += len;
 155        }
 156
 157        end_fw_load(client);
 158
 159        size = fw->size;
 160        release_firmware(fw);
 161
 162        if (is_cx2388x(state)) {
 163                /* Restore GPIO configuration after f/w load */
 164                cx25840_write(client, 0x160, gpio_oe);
 165                cx25840_write(client, 0x164, gpio_da);
 166        }
 167
 168        return check_fw_load(client, size);
 169}
 170
 171MODULE_FIRMWARE(CX2388x_FIRMWARE);
 172MODULE_FIRMWARE(CX231xx_FIRMWARE);
 173MODULE_FIRMWARE(CX25840_FIRMWARE);
 174
 175