xref: /linux/drivers/usb/c67x00/c67x00-ll-hpi.c (revision d6f945044ee3b91a170183e8e34c3db29696d9b8)
1*d6f94504SPeter Korsgaard /*
2*d6f94504SPeter Korsgaard  * c67x00-ll-hpi.c: Cypress C67X00 USB Low level interface using HPI
3*d6f94504SPeter Korsgaard  *
4*d6f94504SPeter Korsgaard  * Copyright (C) 2006-2008 Barco N.V.
5*d6f94504SPeter Korsgaard  *    Derived from the Cypress cy7c67200/300 ezusb linux driver and
6*d6f94504SPeter Korsgaard  *    based on multiple host controller drivers inside the linux kernel.
7*d6f94504SPeter Korsgaard  *
8*d6f94504SPeter Korsgaard  * This program is free software; you can redistribute it and/or modify
9*d6f94504SPeter Korsgaard  * it under the terms of the GNU General Public License as published by
10*d6f94504SPeter Korsgaard  * the Free Software Foundation; either version 2 of the License, or
11*d6f94504SPeter Korsgaard  * (at your option) any later version.
12*d6f94504SPeter Korsgaard  *
13*d6f94504SPeter Korsgaard  * This program is distributed in the hope that it will be useful,
14*d6f94504SPeter Korsgaard  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*d6f94504SPeter Korsgaard  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*d6f94504SPeter Korsgaard  * GNU General Public License for more details.
17*d6f94504SPeter Korsgaard  *
18*d6f94504SPeter Korsgaard  * You should have received a copy of the GNU General Public License
19*d6f94504SPeter Korsgaard  * along with this program; if not, write to the Free Software
20*d6f94504SPeter Korsgaard  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21*d6f94504SPeter Korsgaard  * MA  02110-1301  USA.
22*d6f94504SPeter Korsgaard  */
23*d6f94504SPeter Korsgaard 
24*d6f94504SPeter Korsgaard #include <asm/byteorder.h>
25*d6f94504SPeter Korsgaard #include <linux/io.h>
26*d6f94504SPeter Korsgaard #include <linux/usb/c67x00.h>
27*d6f94504SPeter Korsgaard #include "c67x00.h"
28*d6f94504SPeter Korsgaard 
29*d6f94504SPeter Korsgaard #define COMM_REGS 14
30*d6f94504SPeter Korsgaard 
31*d6f94504SPeter Korsgaard struct c67x00_lcp_int_data {
32*d6f94504SPeter Korsgaard 	u16 regs[COMM_REGS];
33*d6f94504SPeter Korsgaard };
34*d6f94504SPeter Korsgaard 
35*d6f94504SPeter Korsgaard /* -------------------------------------------------------------------------- */
36*d6f94504SPeter Korsgaard /* Interface definitions */
37*d6f94504SPeter Korsgaard 
38*d6f94504SPeter Korsgaard #define COMM_ACK			0x0FED
39*d6f94504SPeter Korsgaard #define COMM_NAK			0xDEAD
40*d6f94504SPeter Korsgaard 
41*d6f94504SPeter Korsgaard #define COMM_RESET			0xFA50
42*d6f94504SPeter Korsgaard #define COMM_EXEC_INT			0xCE01
43*d6f94504SPeter Korsgaard #define COMM_INT_NUM			0x01C2
44*d6f94504SPeter Korsgaard 
45*d6f94504SPeter Korsgaard /* Registers 0 to COMM_REGS-1 */
46*d6f94504SPeter Korsgaard #define COMM_R(x)			(0x01C4 + 2 * (x))
47*d6f94504SPeter Korsgaard 
48*d6f94504SPeter Korsgaard #define HUSB_SIE_pCurrentTDPtr(x)	((x) ? 0x01B2 : 0x01B0)
49*d6f94504SPeter Korsgaard #define HUSB_SIE_pTDListDone_Sem(x)	((x) ? 0x01B8 : 0x01B6)
50*d6f94504SPeter Korsgaard #define HUSB_pEOT			0x01B4
51*d6f94504SPeter Korsgaard 
52*d6f94504SPeter Korsgaard /* Software interrupts */
53*d6f94504SPeter Korsgaard /* 114, 115: */
54*d6f94504SPeter Korsgaard #define HUSB_SIE_INIT_INT(x)		((x) ? 0x0073 : 0x0072)
55*d6f94504SPeter Korsgaard #define HUSB_RESET_INT			0x0074
56*d6f94504SPeter Korsgaard 
57*d6f94504SPeter Korsgaard #define SUSB_INIT_INT			0x0071
58*d6f94504SPeter Korsgaard #define SUSB_INIT_INT_LOC		(SUSB_INIT_INT * 2)
59*d6f94504SPeter Korsgaard 
60*d6f94504SPeter Korsgaard /* -----------------------------------------------------------------------
61*d6f94504SPeter Korsgaard  * HPI implementation
62*d6f94504SPeter Korsgaard  *
63*d6f94504SPeter Korsgaard  * The c67x00 chip also support control via SPI or HSS serial
64*d6f94504SPeter Korsgaard  * interfaces.  However, this driver assumes that register access can
65*d6f94504SPeter Korsgaard  * be performed from IRQ context.  While this is a safe assuption with
66*d6f94504SPeter Korsgaard  * the HPI interface, it is not true for the serial interfaces.
67*d6f94504SPeter Korsgaard  */
68*d6f94504SPeter Korsgaard 
69*d6f94504SPeter Korsgaard /* HPI registers */
70*d6f94504SPeter Korsgaard #define HPI_DATA	0
71*d6f94504SPeter Korsgaard #define HPI_MAILBOX	1
72*d6f94504SPeter Korsgaard #define HPI_ADDR	2
73*d6f94504SPeter Korsgaard #define HPI_STATUS	3
74*d6f94504SPeter Korsgaard 
75*d6f94504SPeter Korsgaard static inline u16 hpi_read_reg(struct c67x00_device *dev, int reg)
76*d6f94504SPeter Korsgaard {
77*d6f94504SPeter Korsgaard 	return __raw_readw(dev->hpi.base + reg * dev->hpi.regstep);
78*d6f94504SPeter Korsgaard }
79*d6f94504SPeter Korsgaard 
80*d6f94504SPeter Korsgaard static inline void hpi_write_reg(struct c67x00_device *dev, int reg, u16 value)
81*d6f94504SPeter Korsgaard {
82*d6f94504SPeter Korsgaard 	__raw_writew(value, dev->hpi.base + reg * dev->hpi.regstep);
83*d6f94504SPeter Korsgaard }
84*d6f94504SPeter Korsgaard 
85*d6f94504SPeter Korsgaard static inline u16 hpi_read_word_nolock(struct c67x00_device *dev, u16 reg)
86*d6f94504SPeter Korsgaard {
87*d6f94504SPeter Korsgaard 	hpi_write_reg(dev, HPI_ADDR, reg);
88*d6f94504SPeter Korsgaard 	return hpi_read_reg(dev, HPI_DATA);
89*d6f94504SPeter Korsgaard }
90*d6f94504SPeter Korsgaard 
91*d6f94504SPeter Korsgaard static u16 hpi_read_word(struct c67x00_device *dev, u16 reg)
92*d6f94504SPeter Korsgaard {
93*d6f94504SPeter Korsgaard 	u16 value;
94*d6f94504SPeter Korsgaard 	unsigned long flags;
95*d6f94504SPeter Korsgaard 
96*d6f94504SPeter Korsgaard 	spin_lock_irqsave(&dev->hpi.lock, flags);
97*d6f94504SPeter Korsgaard 	value = hpi_read_word_nolock(dev, reg);
98*d6f94504SPeter Korsgaard 	spin_unlock_irqrestore(&dev->hpi.lock, flags);
99*d6f94504SPeter Korsgaard 
100*d6f94504SPeter Korsgaard 	return value;
101*d6f94504SPeter Korsgaard }
102*d6f94504SPeter Korsgaard 
103*d6f94504SPeter Korsgaard static void hpi_write_word_nolock(struct c67x00_device *dev, u16 reg, u16 value)
104*d6f94504SPeter Korsgaard {
105*d6f94504SPeter Korsgaard 	hpi_write_reg(dev, HPI_ADDR, reg);
106*d6f94504SPeter Korsgaard 	hpi_write_reg(dev, HPI_DATA, value);
107*d6f94504SPeter Korsgaard }
108*d6f94504SPeter Korsgaard 
109*d6f94504SPeter Korsgaard static void hpi_write_word(struct c67x00_device *dev, u16 reg, u16 value)
110*d6f94504SPeter Korsgaard {
111*d6f94504SPeter Korsgaard 	unsigned long flags;
112*d6f94504SPeter Korsgaard 
113*d6f94504SPeter Korsgaard 	spin_lock_irqsave(&dev->hpi.lock, flags);
114*d6f94504SPeter Korsgaard 	hpi_write_word_nolock(dev, reg, value);
115*d6f94504SPeter Korsgaard 	spin_unlock_irqrestore(&dev->hpi.lock, flags);
116*d6f94504SPeter Korsgaard }
117*d6f94504SPeter Korsgaard 
118*d6f94504SPeter Korsgaard /*
119*d6f94504SPeter Korsgaard  * Only data is little endian, addr has cpu endianess
120*d6f94504SPeter Korsgaard  */
121*d6f94504SPeter Korsgaard static void hpi_write_words_le16(struct c67x00_device *dev, u16 addr,
122*d6f94504SPeter Korsgaard 				 u16 *data, u16 count)
123*d6f94504SPeter Korsgaard {
124*d6f94504SPeter Korsgaard 	unsigned long flags;
125*d6f94504SPeter Korsgaard 	int i;
126*d6f94504SPeter Korsgaard 
127*d6f94504SPeter Korsgaard 	spin_lock_irqsave(&dev->hpi.lock, flags);
128*d6f94504SPeter Korsgaard 
129*d6f94504SPeter Korsgaard 	hpi_write_reg(dev, HPI_ADDR, addr);
130*d6f94504SPeter Korsgaard 	for (i = 0; i < count; i++)
131*d6f94504SPeter Korsgaard 		hpi_write_reg(dev, HPI_DATA, cpu_to_le16(*data++));
132*d6f94504SPeter Korsgaard 
133*d6f94504SPeter Korsgaard 	spin_unlock_irqrestore(&dev->hpi.lock, flags);
134*d6f94504SPeter Korsgaard }
135*d6f94504SPeter Korsgaard 
136*d6f94504SPeter Korsgaard /*
137*d6f94504SPeter Korsgaard  * Only data is little endian, addr has cpu endianess
138*d6f94504SPeter Korsgaard  */
139*d6f94504SPeter Korsgaard static void hpi_read_words_le16(struct c67x00_device *dev, u16 addr,
140*d6f94504SPeter Korsgaard 				u16 *data, u16 count)
141*d6f94504SPeter Korsgaard {
142*d6f94504SPeter Korsgaard 	unsigned long flags;
143*d6f94504SPeter Korsgaard 	int i;
144*d6f94504SPeter Korsgaard 
145*d6f94504SPeter Korsgaard 	spin_lock_irqsave(&dev->hpi.lock, flags);
146*d6f94504SPeter Korsgaard 	hpi_write_reg(dev, HPI_ADDR, addr);
147*d6f94504SPeter Korsgaard 	for (i = 0; i < count; i++)
148*d6f94504SPeter Korsgaard 		*data++ = le16_to_cpu(hpi_read_reg(dev, HPI_DATA));
149*d6f94504SPeter Korsgaard 
150*d6f94504SPeter Korsgaard 	spin_unlock_irqrestore(&dev->hpi.lock, flags);
151*d6f94504SPeter Korsgaard }
152*d6f94504SPeter Korsgaard 
153*d6f94504SPeter Korsgaard static void hpi_set_bits(struct c67x00_device *dev, u16 reg, u16 mask)
154*d6f94504SPeter Korsgaard {
155*d6f94504SPeter Korsgaard 	u16 value;
156*d6f94504SPeter Korsgaard 	unsigned long flags;
157*d6f94504SPeter Korsgaard 
158*d6f94504SPeter Korsgaard 	spin_lock_irqsave(&dev->hpi.lock, flags);
159*d6f94504SPeter Korsgaard 	value = hpi_read_word_nolock(dev, reg);
160*d6f94504SPeter Korsgaard 	hpi_write_word_nolock(dev, reg, value | mask);
161*d6f94504SPeter Korsgaard 	spin_unlock_irqrestore(&dev->hpi.lock, flags);
162*d6f94504SPeter Korsgaard }
163*d6f94504SPeter Korsgaard 
164*d6f94504SPeter Korsgaard static void hpi_clear_bits(struct c67x00_device *dev, u16 reg, u16 mask)
165*d6f94504SPeter Korsgaard {
166*d6f94504SPeter Korsgaard 	u16 value;
167*d6f94504SPeter Korsgaard 	unsigned long flags;
168*d6f94504SPeter Korsgaard 
169*d6f94504SPeter Korsgaard 	spin_lock_irqsave(&dev->hpi.lock, flags);
170*d6f94504SPeter Korsgaard 	value = hpi_read_word_nolock(dev, reg);
171*d6f94504SPeter Korsgaard 	hpi_write_word_nolock(dev, reg, value & ~mask);
172*d6f94504SPeter Korsgaard 	spin_unlock_irqrestore(&dev->hpi.lock, flags);
173*d6f94504SPeter Korsgaard }
174*d6f94504SPeter Korsgaard 
175*d6f94504SPeter Korsgaard static u16 hpi_recv_mbox(struct c67x00_device *dev)
176*d6f94504SPeter Korsgaard {
177*d6f94504SPeter Korsgaard 	u16 value;
178*d6f94504SPeter Korsgaard 	unsigned long flags;
179*d6f94504SPeter Korsgaard 
180*d6f94504SPeter Korsgaard 	spin_lock_irqsave(&dev->hpi.lock, flags);
181*d6f94504SPeter Korsgaard 	value = hpi_read_reg(dev, HPI_MAILBOX);
182*d6f94504SPeter Korsgaard 	spin_unlock_irqrestore(&dev->hpi.lock, flags);
183*d6f94504SPeter Korsgaard 
184*d6f94504SPeter Korsgaard 	return value;
185*d6f94504SPeter Korsgaard }
186*d6f94504SPeter Korsgaard 
187*d6f94504SPeter Korsgaard static u16 hpi_send_mbox(struct c67x00_device *dev, u16 value)
188*d6f94504SPeter Korsgaard {
189*d6f94504SPeter Korsgaard 	unsigned long flags;
190*d6f94504SPeter Korsgaard 
191*d6f94504SPeter Korsgaard 	spin_lock_irqsave(&dev->hpi.lock, flags);
192*d6f94504SPeter Korsgaard 	hpi_write_reg(dev, HPI_MAILBOX, value);
193*d6f94504SPeter Korsgaard 	spin_unlock_irqrestore(&dev->hpi.lock, flags);
194*d6f94504SPeter Korsgaard 
195*d6f94504SPeter Korsgaard 	return value;
196*d6f94504SPeter Korsgaard }
197*d6f94504SPeter Korsgaard 
198*d6f94504SPeter Korsgaard u16 c67x00_ll_hpi_status(struct c67x00_device *dev)
199*d6f94504SPeter Korsgaard {
200*d6f94504SPeter Korsgaard 	u16 value;
201*d6f94504SPeter Korsgaard 	unsigned long flags;
202*d6f94504SPeter Korsgaard 
203*d6f94504SPeter Korsgaard 	spin_lock_irqsave(&dev->hpi.lock, flags);
204*d6f94504SPeter Korsgaard 	value = hpi_read_reg(dev, HPI_STATUS);
205*d6f94504SPeter Korsgaard 	spin_unlock_irqrestore(&dev->hpi.lock, flags);
206*d6f94504SPeter Korsgaard 
207*d6f94504SPeter Korsgaard 	return value;
208*d6f94504SPeter Korsgaard }
209*d6f94504SPeter Korsgaard 
210*d6f94504SPeter Korsgaard void c67x00_ll_hpi_reg_init(struct c67x00_device *dev)
211*d6f94504SPeter Korsgaard {
212*d6f94504SPeter Korsgaard 	int i;
213*d6f94504SPeter Korsgaard 
214*d6f94504SPeter Korsgaard 	hpi_recv_mbox(dev);
215*d6f94504SPeter Korsgaard 	c67x00_ll_hpi_status(dev);
216*d6f94504SPeter Korsgaard 	hpi_write_word(dev, HPI_IRQ_ROUTING_REG, 0);
217*d6f94504SPeter Korsgaard 
218*d6f94504SPeter Korsgaard 	for (i = 0; i < C67X00_SIES; i++) {
219*d6f94504SPeter Korsgaard 		hpi_write_word(dev, SIEMSG_REG(i), 0);
220*d6f94504SPeter Korsgaard 		hpi_read_word(dev, SIEMSG_REG(i));
221*d6f94504SPeter Korsgaard 	}
222*d6f94504SPeter Korsgaard }
223*d6f94504SPeter Korsgaard 
224*d6f94504SPeter Korsgaard void c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie)
225*d6f94504SPeter Korsgaard {
226*d6f94504SPeter Korsgaard 	hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG,
227*d6f94504SPeter Korsgaard 		     SOFEOP_TO_HPI_EN(sie->sie_num));
228*d6f94504SPeter Korsgaard }
229*d6f94504SPeter Korsgaard 
230*d6f94504SPeter Korsgaard void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie)
231*d6f94504SPeter Korsgaard {
232*d6f94504SPeter Korsgaard 	hpi_clear_bits(sie->dev, HPI_IRQ_ROUTING_REG,
233*d6f94504SPeter Korsgaard 		       SOFEOP_TO_HPI_EN(sie->sie_num));
234*d6f94504SPeter Korsgaard }
235*d6f94504SPeter Korsgaard 
236*d6f94504SPeter Korsgaard /* -------------------------------------------------------------------------- */
237*d6f94504SPeter Korsgaard /* Transactions */
238*d6f94504SPeter Korsgaard 
239*d6f94504SPeter Korsgaard static inline u16 ll_recv_msg(struct c67x00_device *dev)
240*d6f94504SPeter Korsgaard {
241*d6f94504SPeter Korsgaard 	u16 res;
242*d6f94504SPeter Korsgaard 
243*d6f94504SPeter Korsgaard 	res = wait_for_completion_timeout(&dev->hpi.lcp.msg_received, 5 * HZ);
244*d6f94504SPeter Korsgaard 	WARN_ON(!res);
245*d6f94504SPeter Korsgaard 
246*d6f94504SPeter Korsgaard 	return (res == 0) ? -EIO : 0;
247*d6f94504SPeter Korsgaard }
248*d6f94504SPeter Korsgaard 
249*d6f94504SPeter Korsgaard /* -------------------------------------------------------------------------- */
250*d6f94504SPeter Korsgaard /* General functions */
251*d6f94504SPeter Korsgaard 
252*d6f94504SPeter Korsgaard u16 c67x00_ll_fetch_siemsg(struct c67x00_device *dev, int sie_num)
253*d6f94504SPeter Korsgaard {
254*d6f94504SPeter Korsgaard 	u16 val;
255*d6f94504SPeter Korsgaard 
256*d6f94504SPeter Korsgaard 	val = hpi_read_word(dev, SIEMSG_REG(sie_num));
257*d6f94504SPeter Korsgaard 	/* clear register to allow next message */
258*d6f94504SPeter Korsgaard 	hpi_write_word(dev, SIEMSG_REG(sie_num), 0);
259*d6f94504SPeter Korsgaard 
260*d6f94504SPeter Korsgaard 	return val;
261*d6f94504SPeter Korsgaard }
262*d6f94504SPeter Korsgaard 
263*d6f94504SPeter Korsgaard u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie)
264*d6f94504SPeter Korsgaard {
265*d6f94504SPeter Korsgaard 	return hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num));
266*d6f94504SPeter Korsgaard }
267*d6f94504SPeter Korsgaard 
268*d6f94504SPeter Korsgaard /**
269*d6f94504SPeter Korsgaard  * c67x00_ll_usb_clear_status - clear the USB status bits
270*d6f94504SPeter Korsgaard  */
271*d6f94504SPeter Korsgaard void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits)
272*d6f94504SPeter Korsgaard {
273*d6f94504SPeter Korsgaard 	hpi_write_word(sie->dev, USB_STAT_REG(sie->sie_num), bits);
274*d6f94504SPeter Korsgaard }
275*d6f94504SPeter Korsgaard 
276*d6f94504SPeter Korsgaard u16 c67x00_ll_usb_get_status(struct c67x00_sie *sie)
277*d6f94504SPeter Korsgaard {
278*d6f94504SPeter Korsgaard 	return hpi_read_word(sie->dev, USB_STAT_REG(sie->sie_num));
279*d6f94504SPeter Korsgaard }
280*d6f94504SPeter Korsgaard 
281*d6f94504SPeter Korsgaard /* -------------------------------------------------------------------------- */
282*d6f94504SPeter Korsgaard 
283*d6f94504SPeter Korsgaard static int c67x00_comm_exec_int(struct c67x00_device *dev, u16 nr,
284*d6f94504SPeter Korsgaard 				struct c67x00_lcp_int_data *data)
285*d6f94504SPeter Korsgaard {
286*d6f94504SPeter Korsgaard 	int i, rc;
287*d6f94504SPeter Korsgaard 
288*d6f94504SPeter Korsgaard 	mutex_lock(&dev->hpi.lcp.mutex);
289*d6f94504SPeter Korsgaard 	hpi_write_word(dev, COMM_INT_NUM, nr);
290*d6f94504SPeter Korsgaard 	for (i = 0; i < COMM_REGS; i++)
291*d6f94504SPeter Korsgaard 		hpi_write_word(dev, COMM_R(i), data->regs[i]);
292*d6f94504SPeter Korsgaard 	hpi_send_mbox(dev, COMM_EXEC_INT);
293*d6f94504SPeter Korsgaard 	rc = ll_recv_msg(dev);
294*d6f94504SPeter Korsgaard 	mutex_unlock(&dev->hpi.lcp.mutex);
295*d6f94504SPeter Korsgaard 
296*d6f94504SPeter Korsgaard 	return rc;
297*d6f94504SPeter Korsgaard }
298*d6f94504SPeter Korsgaard 
299*d6f94504SPeter Korsgaard /* -------------------------------------------------------------------------- */
300*d6f94504SPeter Korsgaard 
301*d6f94504SPeter Korsgaard void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status)
302*d6f94504SPeter Korsgaard {
303*d6f94504SPeter Korsgaard 	if ((int_status & MBX_OUT_FLG) == 0)
304*d6f94504SPeter Korsgaard 		return;
305*d6f94504SPeter Korsgaard 
306*d6f94504SPeter Korsgaard 	dev->hpi.lcp.last_msg = hpi_recv_mbox(dev);
307*d6f94504SPeter Korsgaard 	complete(&dev->hpi.lcp.msg_received);
308*d6f94504SPeter Korsgaard }
309*d6f94504SPeter Korsgaard 
310*d6f94504SPeter Korsgaard /* -------------------------------------------------------------------------- */
311*d6f94504SPeter Korsgaard 
312*d6f94504SPeter Korsgaard int c67x00_ll_reset(struct c67x00_device *dev)
313*d6f94504SPeter Korsgaard {
314*d6f94504SPeter Korsgaard 	int rc;
315*d6f94504SPeter Korsgaard 
316*d6f94504SPeter Korsgaard 	mutex_lock(&dev->hpi.lcp.mutex);
317*d6f94504SPeter Korsgaard 	hpi_send_mbox(dev, COMM_RESET);
318*d6f94504SPeter Korsgaard 	rc = ll_recv_msg(dev);
319*d6f94504SPeter Korsgaard 	mutex_unlock(&dev->hpi.lcp.mutex);
320*d6f94504SPeter Korsgaard 
321*d6f94504SPeter Korsgaard 	return rc;
322*d6f94504SPeter Korsgaard }
323*d6f94504SPeter Korsgaard 
324*d6f94504SPeter Korsgaard /* -------------------------------------------------------------------------- */
325*d6f94504SPeter Korsgaard 
326*d6f94504SPeter Korsgaard /**
327*d6f94504SPeter Korsgaard  * c67x00_ll_write_mem_le16 - write into c67x00 memory
328*d6f94504SPeter Korsgaard  * Only data is little endian, addr has cpu endianess.
329*d6f94504SPeter Korsgaard  */
330*d6f94504SPeter Korsgaard void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr,
331*d6f94504SPeter Korsgaard 			      void *data, int len)
332*d6f94504SPeter Korsgaard {
333*d6f94504SPeter Korsgaard 	u8 *buf = data;
334*d6f94504SPeter Korsgaard 
335*d6f94504SPeter Korsgaard 	/* Sanity check */
336*d6f94504SPeter Korsgaard 	if (addr + len > 0xffff) {
337*d6f94504SPeter Korsgaard 		dev_err(&dev->pdev->dev,
338*d6f94504SPeter Korsgaard 			"Trying to write beyond writable region!\n");
339*d6f94504SPeter Korsgaard 		return;
340*d6f94504SPeter Korsgaard 	}
341*d6f94504SPeter Korsgaard 
342*d6f94504SPeter Korsgaard 	if (addr & 0x01) {
343*d6f94504SPeter Korsgaard 		/* unaligned access */
344*d6f94504SPeter Korsgaard 		u16 tmp;
345*d6f94504SPeter Korsgaard 		tmp = hpi_read_word(dev, addr - 1);
346*d6f94504SPeter Korsgaard 		tmp = (tmp & 0x00ff) | (*buf++ << 8);
347*d6f94504SPeter Korsgaard 		hpi_write_word(dev, addr - 1, tmp);
348*d6f94504SPeter Korsgaard 		addr++;
349*d6f94504SPeter Korsgaard 		len--;
350*d6f94504SPeter Korsgaard 	}
351*d6f94504SPeter Korsgaard 
352*d6f94504SPeter Korsgaard 	hpi_write_words_le16(dev, addr, (u16 *)buf, len / 2);
353*d6f94504SPeter Korsgaard 	buf += len & ~0x01;
354*d6f94504SPeter Korsgaard 	addr += len & ~0x01;
355*d6f94504SPeter Korsgaard 	len &= 0x01;
356*d6f94504SPeter Korsgaard 
357*d6f94504SPeter Korsgaard 	if (len) {
358*d6f94504SPeter Korsgaard 		u16 tmp;
359*d6f94504SPeter Korsgaard 		tmp = hpi_read_word(dev, addr);
360*d6f94504SPeter Korsgaard 		tmp = (tmp & 0xff00) | *buf;
361*d6f94504SPeter Korsgaard 		hpi_write_word(dev, addr, tmp);
362*d6f94504SPeter Korsgaard 	}
363*d6f94504SPeter Korsgaard }
364*d6f94504SPeter Korsgaard 
365*d6f94504SPeter Korsgaard /**
366*d6f94504SPeter Korsgaard  * c67x00_ll_read_mem_le16 - read from c67x00 memory
367*d6f94504SPeter Korsgaard  * Only data is little endian, addr has cpu endianess.
368*d6f94504SPeter Korsgaard  */
369*d6f94504SPeter Korsgaard void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr,
370*d6f94504SPeter Korsgaard 			     void *data, int len)
371*d6f94504SPeter Korsgaard {
372*d6f94504SPeter Korsgaard 	u8 *buf = data;
373*d6f94504SPeter Korsgaard 
374*d6f94504SPeter Korsgaard 	if (addr & 0x01) {
375*d6f94504SPeter Korsgaard 		/* unaligned access */
376*d6f94504SPeter Korsgaard 		u16 tmp;
377*d6f94504SPeter Korsgaard 		tmp = hpi_read_word(dev, addr - 1);
378*d6f94504SPeter Korsgaard 		*buf++ = (tmp >> 8) & 0x00ff;
379*d6f94504SPeter Korsgaard 		addr++;
380*d6f94504SPeter Korsgaard 		len--;
381*d6f94504SPeter Korsgaard 	}
382*d6f94504SPeter Korsgaard 
383*d6f94504SPeter Korsgaard 	hpi_read_words_le16(dev, addr, (u16 *)buf, len / 2);
384*d6f94504SPeter Korsgaard 	buf += len & ~0x01;
385*d6f94504SPeter Korsgaard 	addr += len & ~0x01;
386*d6f94504SPeter Korsgaard 	len &= 0x01;
387*d6f94504SPeter Korsgaard 
388*d6f94504SPeter Korsgaard 	if (len) {
389*d6f94504SPeter Korsgaard 		u16 tmp;
390*d6f94504SPeter Korsgaard 		tmp = hpi_read_word(dev, addr);
391*d6f94504SPeter Korsgaard 		*buf = tmp & 0x00ff;
392*d6f94504SPeter Korsgaard 	}
393*d6f94504SPeter Korsgaard }
394*d6f94504SPeter Korsgaard 
395*d6f94504SPeter Korsgaard /* -------------------------------------------------------------------------- */
396*d6f94504SPeter Korsgaard 
397*d6f94504SPeter Korsgaard void c67x00_ll_init(struct c67x00_device *dev)
398*d6f94504SPeter Korsgaard {
399*d6f94504SPeter Korsgaard 	mutex_init(&dev->hpi.lcp.mutex);
400*d6f94504SPeter Korsgaard 	init_completion(&dev->hpi.lcp.msg_received);
401*d6f94504SPeter Korsgaard }
402*d6f94504SPeter Korsgaard 
403*d6f94504SPeter Korsgaard void c67x00_ll_release(struct c67x00_device *dev)
404*d6f94504SPeter Korsgaard {
405*d6f94504SPeter Korsgaard }
406