11ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez/*
21ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * Intel Wireless UWB Link 1480
31ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * Main driver
41ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez *
51ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * Copyright (C) 2005-2006 Intel Corporation
61ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
71ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez *
81ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * This program is free software; you can redistribute it and/or
91ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * modify it under the terms of the GNU General Public License version
101ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * 2 as published by the Free Software Foundation.
111ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez *
121ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * This program is distributed in the hope that it will be useful,
131ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * but WITHOUT ANY WARRANTY; without even the implied warranty of
141ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
151ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * GNU General Public License for more details.
161ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez *
171ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * You should have received a copy of the GNU General Public License
181ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * along with this program; if not, write to the Free Software
191ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
201ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * 02110-1301, USA.
211ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez *
221ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez *
231ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * Common code for firmware upload used by the USB and PCI version;
241ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * i1480_fw_upload() takes a device descriptor and uses the function
251ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * pointers it provides to upload firmware and prepare the PHY.
261ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez *
271ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * As well, provides common functions used by the rest of the code.
281ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez */
291ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez#include "i1480-dfu.h"
301ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez#include <linux/errno.h>
311ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez#include <linux/delay.h>
321ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez#include <linux/pci.h>
331ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez#include <linux/device.h>
341ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez#include <linux/uwb.h>
351ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez#include <linux/random.h>
36475c0a6b2cff037ca522d3aff839024ab30ed7ebPaul Gortmaker#include <linux/export.h>
371ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez
38bce83697c5fe84a7a5d38c96fbbe43b4bc028c3eDavid Vrabel/*
39b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo * i1480_rceb_check - Check RCEB for expected field values
40b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo * @i1480: pointer to device for which RCEB is being checked
41b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo * @rceb: RCEB being checked
42b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo * @cmd: which command the RCEB is related to
43b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo * @context: expected context
44b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo * @expected_type: expected event type
45b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo * @expected_event: expected event
46b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo *
47b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo * If @cmd is NULL, do not print error messages, but still return an error
48b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo * code.
49b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo *
50b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo * Return 0 if @rceb matches the expected values, -EINVAL otherwise.
51b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo */
521ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalezint i1480_rceb_check(const struct i1480 *i1480, const struct uwb_rceb *rceb,
53b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo		     const char *cmd, u8 context, u8 expected_type,
54b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo		     unsigned expected_event)
551ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez{
561ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	int result = 0;
571ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	struct device *dev = i1480->dev;
581ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	if (rceb->bEventContext != context) {
59b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo		if (cmd)
60b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo			dev_err(dev, "%s: unexpected context id 0x%02x "
61b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo				"(expected 0x%02x)\n", cmd,
62b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo				rceb->bEventContext, context);
631ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		result = -EINVAL;
641ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	}
651ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	if (rceb->bEventType != expected_type) {
66b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo		if (cmd)
67b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo			dev_err(dev, "%s: unexpected event type 0x%02x "
68b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo				"(expected 0x%02x)\n", cmd,
69b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo				rceb->bEventType, expected_type);
701ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		result = -EINVAL;
711ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	}
721ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	if (le16_to_cpu(rceb->wEvent) != expected_event) {
73b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo		if (cmd)
74b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo			dev_err(dev, "%s: unexpected event 0x%04x "
75b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo				"(expected 0x%04x)\n", cmd,
76b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo				le16_to_cpu(rceb->wEvent), expected_event);
771ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		result = -EINVAL;
781ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	}
791ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	return result;
801ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez}
811ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-GonzalezEXPORT_SYMBOL_GPL(i1480_rceb_check);
821ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez
831ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez
84bce83697c5fe84a7a5d38c96fbbe43b4bc028c3eDavid Vrabel/*
851ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * Execute a Radio Control Command
861ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez *
871ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * Command data has to be in i1480->cmd_buf.
881ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez *
891ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * @returns size of the reply data filled in i1480->evt_buf or < 0 errno
901ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez *          code on error.
911ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez */
921ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalezssize_t i1480_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size,
931ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		  size_t reply_size)
941ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez{
951ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	ssize_t result;
961ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	struct uwb_rceb *reply = i1480->evt_buf;
971ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	struct uwb_rccb *cmd = i1480->cmd_buf;
981ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	u16 expected_event = reply->wEvent;
991ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	u8 expected_type = reply->bEventType;
1001ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	u8 context;
1011ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez
1021ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	init_completion(&i1480->evt_complete);
1031ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	i1480->evt_result = -EINPROGRESS;
1041ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	do {
1051ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		get_random_bytes(&context, 1);
1061ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	} while (context == 0x00 || context == 0xff);
1071ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	cmd->bCommandContext = context;
1081ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	result = i1480->cmd(i1480, cmd_name, cmd_size);
1091ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	if (result < 0)
1101ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		goto error;
1111ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	/* wait for the callback to report a event was received */
1121ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	result = wait_for_completion_interruptible_timeout(
1131ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		&i1480->evt_complete, HZ);
1141ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	if (result == 0) {
1151ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		result = -ETIMEDOUT;
1161ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		goto error;
1171ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	}
1181ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	if (result < 0)
1191ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		goto error;
1201ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	result = i1480->evt_result;
1211ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	if (result < 0) {
1221ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		dev_err(i1480->dev, "%s: command reply reception failed: %zd\n",
1231ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez			cmd_name, result);
1241ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		goto error;
1251ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	}
126b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo	/*
127b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo	 * Firmware versions >= 1.4.12224 for IOGear GUWA100U generate a
128b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo	 * spurious notification after firmware is downloaded. So check whether
129b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo	 * the receibed RCEB is such notification before assuming that the
130b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo	 * command has failed.
131b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo	 */
132b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo	if (i1480_rceb_check(i1480, i1480->evt_buf, NULL,
133b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo			     0, 0xfd, 0x0022) == 0) {
134b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo		/* Now wait for the actual RCEB for this command. */
135b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo		result = i1480->wait_init_done(i1480);
136b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo		if (result < 0)
137b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo			goto error;
138b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo		result = i1480->evt_result;
139b5784f10d559b3c7b25874b21702ad0907b6fcb7Anderson Lizardo	}
1401ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	if (result != reply_size) {
1411ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		dev_err(i1480->dev, "%s returned only %zu bytes, %zu expected\n",
1421ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez			cmd_name, result, reply_size);
1431ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		result = -EINVAL;
1441ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		goto error;
1451ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	}
1461ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	/* Verify we got the right event in response */
1471ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	result = i1480_rceb_check(i1480, i1480->evt_buf, cmd_name, context,
1481ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez				  expected_type, expected_event);
1491ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalezerror:
1501ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	return result;
1511ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez}
1521ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-GonzalezEXPORT_SYMBOL_GPL(i1480_cmd);
1531ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez
1541ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez
1551ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalezstatic
1561ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalezint i1480_print_state(struct i1480 *i1480)
1571ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez{
1581ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	int result;
1591ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	u32 *buf = (u32 *) i1480->cmd_buf;
1601ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez
1611ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	result = i1480->read(i1480, 0x80080000, 2 * sizeof(*buf));
1621ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	if (result < 0) {
1631ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		dev_err(i1480->dev, "cannot read U & L states: %d\n", result);
1641ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		goto error;
1651ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	}
1661ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	dev_info(i1480->dev, "state U 0x%08x, L 0x%08x\n", buf[0], buf[1]);
1671ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalezerror:
1681ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	return result;
1691ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez}
1701ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez
1711ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez
1721ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez/*
1731ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * PCI probe, firmware uploader
1741ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez *
1751ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez * _mac_fw_upload() will call rc_setup(), which needs an rc_release().
1761ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez */
1771ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalezint i1480_fw_upload(struct i1480 *i1480)
1781ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez{
1791ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	int result;
1801ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez
1811ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	result = i1480_pre_fw_upload(i1480);	/* PHY pre fw */
1821ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	if (result < 0 && result != -ENOENT) {
1831ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		i1480_print_state(i1480);
1841ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		goto error;
1851ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	}
1861ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	result = i1480_mac_fw_upload(i1480);	/* MAC fw */
1871ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	if (result < 0) {
1881ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		if (result == -ENOENT)
1891ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez			dev_err(i1480->dev, "Cannot locate MAC FW file '%s'\n",
1901ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez				i1480->mac_fw_name);
1911ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		else
1921ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez			i1480_print_state(i1480);
1931ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		goto error;
1941ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	}
1951ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	result = i1480_phy_fw_upload(i1480);	/* PHY fw */
1961ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	if (result < 0 && result != -ENOENT) {
1971ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		i1480_print_state(i1480);
1981ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		goto error_rc_release;
1991ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	}
2008c7e8cb85557cc500122f3e489936582b7d11a7cAnderson Lizardo	/*
2018c7e8cb85557cc500122f3e489936582b7d11a7cAnderson Lizardo	 * FIXME: find some reliable way to check whether firmware is running
2028c7e8cb85557cc500122f3e489936582b7d11a7cAnderson Lizardo	 * properly. Maybe use some standard request that has no side effects?
2038c7e8cb85557cc500122f3e489936582b7d11a7cAnderson Lizardo	 */
2041ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	dev_info(i1480->dev, "firmware uploaded successfully\n");
2051ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalezerror_rc_release:
2061ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	if (i1480->rc_release)
2071ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez		i1480->rc_release(i1480);
2081ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	result = 0;
2091ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalezerror:
2101ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez	return result;
2111ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-Gonzalez}
2121ba47da527121ff704f4e9f27a12c9f32db05022Inaky Perez-GonzalezEXPORT_SYMBOL_GPL(i1480_fw_upload);
213