Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
phy.c
Go to the documentation of this file.
1 /*
2  * Intel Wireless UWB Link 1480
3  * PHY parameters upload
4  *
5  * Copyright (C) 2005-2006 Intel Corporation
6  * Inaky Perez-Gonzalez <[email protected]>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License version
10  * 2 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  * 02110-1301, USA.
21  *
22  *
23  * Code for uploading the PHY parameters to the PHY through the UWB
24  * Radio Control interface.
25  *
26  * We just send the data through the MPI interface using HWA-like
27  * commands and then reset the PHY to make sure it is ok.
28  */
29 #include <linux/delay.h>
30 #include <linux/device.h>
31 #include <linux/firmware.h>
32 #include <linux/usb/wusb.h>
33 #include "i1480-dfu.h"
34 
35 
51 static
52 int i1480_mpi_write(struct i1480 *i1480, const void *data, size_t size)
53 {
54  int result;
55  struct i1480_cmd_mpi_write *cmd = i1480->cmd_buf;
56  struct i1480_evt_confirm *reply = i1480->evt_buf;
57 
58  BUG_ON(size > 480);
59  result = -ENOMEM;
60  cmd->rccb.bCommandType = i1480_CET_VS1;
61  cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_WRITE);
62  cmd->size = cpu_to_le16(size);
63  memcpy(cmd->data, data, size);
64  reply->rceb.bEventType = i1480_CET_VS1;
65  reply->rceb.wEvent = i1480_CMD_MPI_WRITE;
66  result = i1480_cmd(i1480, "MPI-WRITE", sizeof(*cmd) + size, sizeof(*reply));
67  if (result < 0)
68  goto out;
69  if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
70  dev_err(i1480->dev, "MPI-WRITE: command execution failed: %d\n",
71  reply->bResultCode);
72  result = -EIO;
73  }
74 out:
75  return result;
76 }
77 
78 
99 static
100 int i1480_mpi_read(struct i1480 *i1480, u8 *data, u16 srcaddr, size_t size)
101 {
102  int result;
103  struct i1480_cmd_mpi_read *cmd = i1480->cmd_buf;
104  struct i1480_evt_mpi_read *reply = i1480->evt_buf;
105  unsigned cnt;
106 
107  memset(i1480->cmd_buf, 0x69, 512);
108  memset(i1480->evt_buf, 0x69, 512);
109 
110  BUG_ON(size > (i1480->buf_size - sizeof(*reply)) / 3);
111  result = -ENOMEM;
112  cmd->rccb.bCommandType = i1480_CET_VS1;
113  cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_READ);
114  cmd->size = cpu_to_le16(3*size);
115  for (cnt = 0; cnt < size; cnt++) {
116  cmd->data[cnt].page = (srcaddr + cnt) >> 8;
117  cmd->data[cnt].offset = (srcaddr + cnt) & 0xff;
118  }
119  reply->rceb.bEventType = i1480_CET_VS1;
120  reply->rceb.wEvent = i1480_CMD_MPI_READ;
121  result = i1480_cmd(i1480, "MPI-READ", sizeof(*cmd) + 2*size,
122  sizeof(*reply) + 3*size);
123  if (result < 0)
124  goto out;
125  if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
126  dev_err(i1480->dev, "MPI-READ: command execution failed: %d\n",
127  reply->bResultCode);
128  result = -EIO;
129  }
130  for (cnt = 0; cnt < size; cnt++) {
131  if (reply->data[cnt].page != (srcaddr + cnt) >> 8)
132  dev_err(i1480->dev, "MPI-READ: page inconsistency at "
133  "index %u: expected 0x%02x, got 0x%02x\n", cnt,
134  (srcaddr + cnt) >> 8, reply->data[cnt].page);
135  if (reply->data[cnt].offset != ((srcaddr + cnt) & 0x00ff))
136  dev_err(i1480->dev, "MPI-READ: offset inconsistency at "
137  "index %u: expected 0x%02x, got 0x%02x\n", cnt,
138  (srcaddr + cnt) & 0x00ff,
139  reply->data[cnt].offset);
140  data[cnt] = reply->data[cnt].value;
141  }
142  result = 0;
143 out:
144  return result;
145 }
146 
147 
162 int i1480_phy_fw_upload(struct i1480 *i1480)
163 {
164  int result;
165  const struct firmware *fw;
166  const char *data_itr, *data_top;
167  const size_t MAX_BLK_SIZE = 480; /* 160 triads */
168  size_t data_size;
169  u8 phy_stat;
170 
171  result = request_firmware(&fw, i1480->phy_fw_name, i1480->dev);
172  if (result < 0)
173  goto out;
174  /* Loop writing data in chunks as big as possible until done. */
175  for (data_itr = fw->data, data_top = data_itr + fw->size;
176  data_itr < data_top; data_itr += MAX_BLK_SIZE) {
177  data_size = min(MAX_BLK_SIZE, (size_t) (data_top - data_itr));
178  result = i1480_mpi_write(i1480, data_itr, data_size);
179  if (result < 0)
180  goto error_mpi_write;
181  }
182  /* Read MPI page 0, offset 6; if 0, PHY was initialized correctly. */
183  result = i1480_mpi_read(i1480, &phy_stat, 0x0006, 1);
184  if (result < 0) {
185  dev_err(i1480->dev, "PHY: can't get status: %d\n", result);
186  goto error_mpi_status;
187  }
188  if (phy_stat != 0) {
189  result = -ENODEV;
190  dev_info(i1480->dev, "error, PHY not ready: %u\n", phy_stat);
191  goto error_phy_status;
192  }
193  dev_info(i1480->dev, "PHY fw '%s': uploaded\n", i1480->phy_fw_name);
194 error_phy_status:
195 error_mpi_status:
196 error_mpi_write:
197  release_firmware(fw);
198  if (result < 0)
199  dev_err(i1480->dev, "PHY fw '%s': failed to upload (%d), "
200  "power cycle device\n", i1480->phy_fw_name, result);
201 out:
202  return result;
203 }