Path: blob/master/drivers/media/video/cx25840/cx25840-firmware.c
17895 views
/* cx25840 firmware functions1*2* This program is free software; you can redistribute it and/or3* modify it under the terms of the GNU General Public License4* as published by the Free Software Foundation; either version 25* of the License, or (at your option) any later version.6*7* This program is distributed in the hope that it will be useful,8* but WITHOUT ANY WARRANTY; without even the implied warranty of9* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the10* GNU General Public License for more details.11*12* You should have received a copy of the GNU General Public License13* along with this program; if not, write to the Free Software14* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.15*/1617#include <linux/module.h>18#include <linux/i2c.h>19#include <linux/firmware.h>20#include <media/v4l2-common.h>21#include <media/cx25840.h>2223#include "cx25840-core.h"2425/*26* Mike Isely <[email protected]> - The FWSEND parameter controls the27* size of the firmware chunks sent down the I2C bus to the chip.28* Previously this had been set to 1024 but unfortunately some I2C29* implementations can't transfer data in such big gulps.30* Specifically, the pvrusb2 driver has a hard limit of around 6031* bytes, due to the encapsulation there of I2C traffic into USB32* messages. So we have to significantly reduce this parameter.33*/34#define FWSEND 483536#define FWDEV(x) &((x)->dev)3738static char *firmware = "";3940module_param(firmware, charp, 0444);4142MODULE_PARM_DESC(firmware, "Firmware image to load");4344static void start_fw_load(struct i2c_client *client)45{46/* DL_ADDR_LB=0 DL_ADDR_HB=0 */47cx25840_write(client, 0x800, 0x00);48cx25840_write(client, 0x801, 0x00);49// DL_MAP=3 DL_AUTO_INC=0 DL_ENABLE=150cx25840_write(client, 0x803, 0x0b);51/* AUTO_INC_DIS=1 */52cx25840_write(client, 0x000, 0x20);53}5455static void end_fw_load(struct i2c_client *client)56{57/* AUTO_INC_DIS=0 */58cx25840_write(client, 0x000, 0x00);59/* DL_ENABLE=0 */60cx25840_write(client, 0x803, 0x03);61}6263static const char *get_fw_name(struct i2c_client *client)64{65struct cx25840_state *state = to_state(i2c_get_clientdata(client));6667if (firmware[0])68return firmware;69if (is_cx2388x(state))70return "v4l-cx23885-avcore-01.fw";71if (is_cx231xx(state))72return "v4l-cx231xx-avcore-01.fw";73return "v4l-cx25840.fw";74}7576static int check_fw_load(struct i2c_client *client, int size)77{78/* DL_ADDR_HB DL_ADDR_LB */79int s = cx25840_read(client, 0x801) << 8;80s |= cx25840_read(client, 0x800);8182if (size != s) {83v4l_err(client, "firmware %s load failed\n",84get_fw_name(client));85return -EINVAL;86}8788v4l_info(client, "loaded %s firmware (%d bytes)\n",89get_fw_name(client), size);90return 0;91}9293static int fw_write(struct i2c_client *client, const u8 *data, int size)94{95if (i2c_master_send(client, data, size) < size) {96v4l_err(client, "firmware load i2c failure\n");97return -ENOSYS;98}99100return 0;101}102103int cx25840_loadfw(struct i2c_client *client)104{105struct cx25840_state *state = to_state(i2c_get_clientdata(client));106const struct firmware *fw = NULL;107u8 buffer[FWSEND];108const u8 *ptr;109const char *fwname = get_fw_name(client);110int size, retval;111int MAX_BUF_SIZE = FWSEND;112u32 gpio_oe = 0, gpio_da = 0;113114if (is_cx2388x(state)) {115/* Preserve the GPIO OE and output bits */116gpio_oe = cx25840_read(client, 0x160);117gpio_da = cx25840_read(client, 0x164);118}119120if (is_cx231xx(state) && MAX_BUF_SIZE > 16) {121v4l_err(client, " Firmware download size changed to 16 bytes max length\n");122MAX_BUF_SIZE = 16; /* cx231xx cannot accept more than 16 bytes at a time */123}124125if (request_firmware(&fw, fwname, FWDEV(client)) != 0) {126v4l_err(client, "unable to open firmware %s\n", fwname);127return -EINVAL;128}129130start_fw_load(client);131132buffer[0] = 0x08;133buffer[1] = 0x02;134135size = fw->size;136ptr = fw->data;137while (size > 0) {138int len = min(MAX_BUF_SIZE - 2, size);139140memcpy(buffer + 2, ptr, len);141142retval = fw_write(client, buffer, len + 2);143144if (retval < 0) {145release_firmware(fw);146return retval;147}148149size -= len;150ptr += len;151}152153end_fw_load(client);154155size = fw->size;156release_firmware(fw);157158if (is_cx2388x(state)) {159/* Restore GPIO configuration after f/w load */160cx25840_write(client, 0x160, gpio_oe);161cx25840_write(client, 0x164, gpio_da);162}163164return check_fw_load(client, size);165}166167168