162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * c67x00-ll-hpi.c: Cypress C67X00 USB Low level interface using HPI
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2006-2008 Barco N.V.
662306a36Sopenharmony_ci *    Derived from the Cypress cy7c67200/300 ezusb linux driver and
762306a36Sopenharmony_ci *    based on multiple host controller drivers inside the linux kernel.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <asm/byteorder.h>
1162306a36Sopenharmony_ci#include <linux/delay.h>
1262306a36Sopenharmony_ci#include <linux/io.h>
1362306a36Sopenharmony_ci#include <linux/jiffies.h>
1462306a36Sopenharmony_ci#include <linux/usb/c67x00.h>
1562306a36Sopenharmony_ci#include "c67x00.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define COMM_REGS 14
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistruct c67x00_lcp_int_data {
2062306a36Sopenharmony_ci	u16 regs[COMM_REGS];
2162306a36Sopenharmony_ci};
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
2462306a36Sopenharmony_ci/* Interface definitions */
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define COMM_ACK			0x0FED
2762306a36Sopenharmony_ci#define COMM_NAK			0xDEAD
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define COMM_RESET			0xFA50
3062306a36Sopenharmony_ci#define COMM_EXEC_INT			0xCE01
3162306a36Sopenharmony_ci#define COMM_INT_NUM			0x01C2
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/* Registers 0 to COMM_REGS-1 */
3462306a36Sopenharmony_ci#define COMM_R(x)			(0x01C4 + 2 * (x))
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define HUSB_SIE_pCurrentTDPtr(x)	((x) ? 0x01B2 : 0x01B0)
3762306a36Sopenharmony_ci#define HUSB_SIE_pTDListDone_Sem(x)	((x) ? 0x01B8 : 0x01B6)
3862306a36Sopenharmony_ci#define HUSB_pEOT			0x01B4
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/* Software interrupts */
4162306a36Sopenharmony_ci/* 114, 115: */
4262306a36Sopenharmony_ci#define HUSB_SIE_INIT_INT(x)		((x) ? 0x0073 : 0x0072)
4362306a36Sopenharmony_ci#define HUSB_RESET_INT			0x0074
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define SUSB_INIT_INT			0x0071
4662306a36Sopenharmony_ci#define SUSB_INIT_INT_LOC		(SUSB_INIT_INT * 2)
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* -----------------------------------------------------------------------
4962306a36Sopenharmony_ci * HPI implementation
5062306a36Sopenharmony_ci *
5162306a36Sopenharmony_ci * The c67x00 chip also support control via SPI or HSS serial
5262306a36Sopenharmony_ci * interfaces. However, this driver assumes that register access can
5362306a36Sopenharmony_ci * be performed from IRQ context. While this is a safe assumption with
5462306a36Sopenharmony_ci * the HPI interface, it is not true for the serial interfaces.
5562306a36Sopenharmony_ci */
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/* HPI registers */
5862306a36Sopenharmony_ci#define HPI_DATA	0
5962306a36Sopenharmony_ci#define HPI_MAILBOX	1
6062306a36Sopenharmony_ci#define HPI_ADDR	2
6162306a36Sopenharmony_ci#define HPI_STATUS	3
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/*
6462306a36Sopenharmony_ci * According to CY7C67300 specification (tables 140 and 141) HPI read and
6562306a36Sopenharmony_ci * write cycle duration Tcyc must be at least 6T long, where T is 1/48MHz,
6662306a36Sopenharmony_ci * which is 125ns.
6762306a36Sopenharmony_ci */
6862306a36Sopenharmony_ci#define HPI_T_CYC_NS	125
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic inline u16 hpi_read_reg(struct c67x00_device *dev, int reg)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	ndelay(HPI_T_CYC_NS);
7362306a36Sopenharmony_ci	return __raw_readw(dev->hpi.base + reg * dev->hpi.regstep);
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic inline void hpi_write_reg(struct c67x00_device *dev, int reg, u16 value)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	ndelay(HPI_T_CYC_NS);
7962306a36Sopenharmony_ci	__raw_writew(value, dev->hpi.base + reg * dev->hpi.regstep);
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic inline u16 hpi_read_word_nolock(struct c67x00_device *dev, u16 reg)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	hpi_write_reg(dev, HPI_ADDR, reg);
8562306a36Sopenharmony_ci	return hpi_read_reg(dev, HPI_DATA);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic u16 hpi_read_word(struct c67x00_device *dev, u16 reg)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	u16 value;
9162306a36Sopenharmony_ci	unsigned long flags;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	spin_lock_irqsave(&dev->hpi.lock, flags);
9462306a36Sopenharmony_ci	value = hpi_read_word_nolock(dev, reg);
9562306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->hpi.lock, flags);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	return value;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic void hpi_write_word_nolock(struct c67x00_device *dev, u16 reg, u16 value)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	hpi_write_reg(dev, HPI_ADDR, reg);
10362306a36Sopenharmony_ci	hpi_write_reg(dev, HPI_DATA, value);
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic void hpi_write_word(struct c67x00_device *dev, u16 reg, u16 value)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	unsigned long flags;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	spin_lock_irqsave(&dev->hpi.lock, flags);
11162306a36Sopenharmony_ci	hpi_write_word_nolock(dev, reg, value);
11262306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->hpi.lock, flags);
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/*
11662306a36Sopenharmony_ci * Only data is little endian, addr has cpu endianess
11762306a36Sopenharmony_ci */
11862306a36Sopenharmony_cistatic void hpi_write_words_le16(struct c67x00_device *dev, u16 addr,
11962306a36Sopenharmony_ci				 __le16 *data, u16 count)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	unsigned long flags;
12262306a36Sopenharmony_ci	int i;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	spin_lock_irqsave(&dev->hpi.lock, flags);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	hpi_write_reg(dev, HPI_ADDR, addr);
12762306a36Sopenharmony_ci	for (i = 0; i < count; i++)
12862306a36Sopenharmony_ci		hpi_write_reg(dev, HPI_DATA, le16_to_cpu(*data++));
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->hpi.lock, flags);
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci/*
13462306a36Sopenharmony_ci * Only data is little endian, addr has cpu endianess
13562306a36Sopenharmony_ci */
13662306a36Sopenharmony_cistatic void hpi_read_words_le16(struct c67x00_device *dev, u16 addr,
13762306a36Sopenharmony_ci				__le16 *data, u16 count)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	unsigned long flags;
14062306a36Sopenharmony_ci	int i;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	spin_lock_irqsave(&dev->hpi.lock, flags);
14362306a36Sopenharmony_ci	hpi_write_reg(dev, HPI_ADDR, addr);
14462306a36Sopenharmony_ci	for (i = 0; i < count; i++)
14562306a36Sopenharmony_ci		*data++ = cpu_to_le16(hpi_read_reg(dev, HPI_DATA));
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->hpi.lock, flags);
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic void hpi_set_bits(struct c67x00_device *dev, u16 reg, u16 mask)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	u16 value;
15362306a36Sopenharmony_ci	unsigned long flags;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	spin_lock_irqsave(&dev->hpi.lock, flags);
15662306a36Sopenharmony_ci	value = hpi_read_word_nolock(dev, reg);
15762306a36Sopenharmony_ci	hpi_write_word_nolock(dev, reg, value | mask);
15862306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->hpi.lock, flags);
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic void hpi_clear_bits(struct c67x00_device *dev, u16 reg, u16 mask)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	u16 value;
16462306a36Sopenharmony_ci	unsigned long flags;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	spin_lock_irqsave(&dev->hpi.lock, flags);
16762306a36Sopenharmony_ci	value = hpi_read_word_nolock(dev, reg);
16862306a36Sopenharmony_ci	hpi_write_word_nolock(dev, reg, value & ~mask);
16962306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->hpi.lock, flags);
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic u16 hpi_recv_mbox(struct c67x00_device *dev)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	u16 value;
17562306a36Sopenharmony_ci	unsigned long flags;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	spin_lock_irqsave(&dev->hpi.lock, flags);
17862306a36Sopenharmony_ci	value = hpi_read_reg(dev, HPI_MAILBOX);
17962306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->hpi.lock, flags);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	return value;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic u16 hpi_send_mbox(struct c67x00_device *dev, u16 value)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	unsigned long flags;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	spin_lock_irqsave(&dev->hpi.lock, flags);
18962306a36Sopenharmony_ci	hpi_write_reg(dev, HPI_MAILBOX, value);
19062306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->hpi.lock, flags);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	return value;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ciu16 c67x00_ll_hpi_status(struct c67x00_device *dev)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	u16 value;
19862306a36Sopenharmony_ci	unsigned long flags;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	spin_lock_irqsave(&dev->hpi.lock, flags);
20162306a36Sopenharmony_ci	value = hpi_read_reg(dev, HPI_STATUS);
20262306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->hpi.lock, flags);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	return value;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_civoid c67x00_ll_hpi_reg_init(struct c67x00_device *dev)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	int i;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	hpi_recv_mbox(dev);
21262306a36Sopenharmony_ci	c67x00_ll_hpi_status(dev);
21362306a36Sopenharmony_ci	hpi_write_word(dev, HPI_IRQ_ROUTING_REG, 0);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	for (i = 0; i < C67X00_SIES; i++) {
21662306a36Sopenharmony_ci		hpi_write_word(dev, SIEMSG_REG(i), 0);
21762306a36Sopenharmony_ci		hpi_read_word(dev, SIEMSG_REG(i));
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_civoid c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG,
22462306a36Sopenharmony_ci		     SOFEOP_TO_HPI_EN(sie->sie_num));
22562306a36Sopenharmony_ci}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_civoid c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	hpi_clear_bits(sie->dev, HPI_IRQ_ROUTING_REG,
23062306a36Sopenharmony_ci		       SOFEOP_TO_HPI_EN(sie->sie_num));
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
23462306a36Sopenharmony_ci/* Transactions */
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic inline int ll_recv_msg(struct c67x00_device *dev)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	u16 res;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	res = wait_for_completion_timeout(&dev->hpi.lcp.msg_received, 5 * HZ);
24162306a36Sopenharmony_ci	WARN_ON(!res);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	return (res == 0) ? -EIO : 0;
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
24762306a36Sopenharmony_ci/* General functions */
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ciu16 c67x00_ll_fetch_siemsg(struct c67x00_device *dev, int sie_num)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	u16 val;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	val = hpi_read_word(dev, SIEMSG_REG(sie_num));
25462306a36Sopenharmony_ci	/* clear register to allow next message */
25562306a36Sopenharmony_ci	hpi_write_word(dev, SIEMSG_REG(sie_num), 0);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	return val;
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ciu16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	return hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num));
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci/*
26662306a36Sopenharmony_ci * c67x00_ll_usb_clear_status - clear the USB status bits
26762306a36Sopenharmony_ci */
26862306a36Sopenharmony_civoid c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	hpi_write_word(sie->dev, USB_STAT_REG(sie->sie_num), bits);
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ciu16 c67x00_ll_usb_get_status(struct c67x00_sie *sie)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	return hpi_read_word(sie->dev, USB_STAT_REG(sie->sie_num));
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistatic int c67x00_comm_exec_int(struct c67x00_device *dev, u16 nr,
28162306a36Sopenharmony_ci				struct c67x00_lcp_int_data *data)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	int i, rc;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	mutex_lock(&dev->hpi.lcp.mutex);
28662306a36Sopenharmony_ci	hpi_write_word(dev, COMM_INT_NUM, nr);
28762306a36Sopenharmony_ci	for (i = 0; i < COMM_REGS; i++)
28862306a36Sopenharmony_ci		hpi_write_word(dev, COMM_R(i), data->regs[i]);
28962306a36Sopenharmony_ci	hpi_send_mbox(dev, COMM_EXEC_INT);
29062306a36Sopenharmony_ci	rc = ll_recv_msg(dev);
29162306a36Sopenharmony_ci	mutex_unlock(&dev->hpi.lcp.mutex);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	return rc;
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
29762306a36Sopenharmony_ci/* Host specific functions */
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_civoid c67x00_ll_set_husb_eot(struct c67x00_device *dev, u16 value)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	mutex_lock(&dev->hpi.lcp.mutex);
30262306a36Sopenharmony_ci	hpi_write_word(dev, HUSB_pEOT, value);
30362306a36Sopenharmony_ci	mutex_unlock(&dev->hpi.lcp.mutex);
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic inline void c67x00_ll_husb_sie_init(struct c67x00_sie *sie)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	struct c67x00_device *dev = sie->dev;
30962306a36Sopenharmony_ci	struct c67x00_lcp_int_data data;
31062306a36Sopenharmony_ci	int rc;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	rc = c67x00_comm_exec_int(dev, HUSB_SIE_INIT_INT(sie->sie_num), &data);
31362306a36Sopenharmony_ci	BUG_ON(rc); /* No return path for error code; crash spectacularly */
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_civoid c67x00_ll_husb_reset(struct c67x00_sie *sie, int port)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	struct c67x00_device *dev = sie->dev;
31962306a36Sopenharmony_ci	struct c67x00_lcp_int_data data;
32062306a36Sopenharmony_ci	int rc;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	data.regs[0] = 50;	/* Reset USB port for 50ms */
32362306a36Sopenharmony_ci	data.regs[1] = port | (sie->sie_num << 1);
32462306a36Sopenharmony_ci	rc = c67x00_comm_exec_int(dev, HUSB_RESET_INT, &data);
32562306a36Sopenharmony_ci	BUG_ON(rc); /* No return path for error code; crash spectacularly */
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_civoid c67x00_ll_husb_set_current_td(struct c67x00_sie *sie, u16 addr)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	hpi_write_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num), addr);
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ciu16 c67x00_ll_husb_get_current_td(struct c67x00_sie *sie)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	return hpi_read_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num));
33662306a36Sopenharmony_ci}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ciu16 c67x00_ll_husb_get_frame(struct c67x00_sie *sie)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	return hpi_read_word(sie->dev, HOST_FRAME_REG(sie->sie_num));
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_civoid c67x00_ll_husb_init_host_port(struct c67x00_sie *sie)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	/* Set port into host mode */
34662306a36Sopenharmony_ci	hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), HOST_MODE);
34762306a36Sopenharmony_ci	c67x00_ll_husb_sie_init(sie);
34862306a36Sopenharmony_ci	/* Clear interrupts */
34962306a36Sopenharmony_ci	c67x00_ll_usb_clear_status(sie, HOST_STAT_MASK);
35062306a36Sopenharmony_ci	/* Check */
35162306a36Sopenharmony_ci	if (!(hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num)) & HOST_MODE))
35262306a36Sopenharmony_ci		dev_warn(sie_dev(sie),
35362306a36Sopenharmony_ci			 "SIE %d not set to host mode\n", sie->sie_num);
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_civoid c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	/* Clear connect change */
35962306a36Sopenharmony_ci	c67x00_ll_usb_clear_status(sie, PORT_CONNECT_CHANGE(port));
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	/* Enable interrupts */
36262306a36Sopenharmony_ci	hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG,
36362306a36Sopenharmony_ci		     SOFEOP_TO_CPU_EN(sie->sie_num));
36462306a36Sopenharmony_ci	hpi_set_bits(sie->dev, HOST_IRQ_EN_REG(sie->sie_num),
36562306a36Sopenharmony_ci		     SOF_EOP_IRQ_EN | DONE_IRQ_EN);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	/* Enable pull down transistors */
36862306a36Sopenharmony_ci	hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), PORT_RES_EN(port));
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_civoid c67x00_ll_irq(struct c67x00_device *dev, u16 int_status)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	if ((int_status & MBX_OUT_FLG) == 0)
37662306a36Sopenharmony_ci		return;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	dev->hpi.lcp.last_msg = hpi_recv_mbox(dev);
37962306a36Sopenharmony_ci	complete(&dev->hpi.lcp.msg_received);
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ciint c67x00_ll_reset(struct c67x00_device *dev)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	int rc;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	mutex_lock(&dev->hpi.lcp.mutex);
38962306a36Sopenharmony_ci	hpi_send_mbox(dev, COMM_RESET);
39062306a36Sopenharmony_ci	rc = ll_recv_msg(dev);
39162306a36Sopenharmony_ci	mutex_unlock(&dev->hpi.lcp.mutex);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	return rc;
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci/*
39962306a36Sopenharmony_ci * c67x00_ll_write_mem_le16 - write into c67x00 memory
40062306a36Sopenharmony_ci * Only data is little endian, addr has cpu endianess.
40162306a36Sopenharmony_ci */
40262306a36Sopenharmony_civoid c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr,
40362306a36Sopenharmony_ci			      void *data, int len)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	u8 *buf = data;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	/* Sanity check */
40862306a36Sopenharmony_ci	if (addr + len > 0xffff) {
40962306a36Sopenharmony_ci		dev_err(&dev->pdev->dev,
41062306a36Sopenharmony_ci			"Trying to write beyond writable region!\n");
41162306a36Sopenharmony_ci		return;
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	if (addr & 0x01) {
41562306a36Sopenharmony_ci		/* unaligned access */
41662306a36Sopenharmony_ci		u16 tmp;
41762306a36Sopenharmony_ci		tmp = hpi_read_word(dev, addr - 1);
41862306a36Sopenharmony_ci		tmp = (tmp & 0x00ff) | (*buf++ << 8);
41962306a36Sopenharmony_ci		hpi_write_word(dev, addr - 1, tmp);
42062306a36Sopenharmony_ci		addr++;
42162306a36Sopenharmony_ci		len--;
42262306a36Sopenharmony_ci	}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	hpi_write_words_le16(dev, addr, (__le16 *)buf, len / 2);
42562306a36Sopenharmony_ci	buf += len & ~0x01;
42662306a36Sopenharmony_ci	addr += len & ~0x01;
42762306a36Sopenharmony_ci	len &= 0x01;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	if (len) {
43062306a36Sopenharmony_ci		u16 tmp;
43162306a36Sopenharmony_ci		tmp = hpi_read_word(dev, addr);
43262306a36Sopenharmony_ci		tmp = (tmp & 0xff00) | *buf;
43362306a36Sopenharmony_ci		hpi_write_word(dev, addr, tmp);
43462306a36Sopenharmony_ci	}
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci/*
43862306a36Sopenharmony_ci * c67x00_ll_read_mem_le16 - read from c67x00 memory
43962306a36Sopenharmony_ci * Only data is little endian, addr has cpu endianess.
44062306a36Sopenharmony_ci */
44162306a36Sopenharmony_civoid c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr,
44262306a36Sopenharmony_ci			     void *data, int len)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	u8 *buf = data;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	if (addr & 0x01) {
44762306a36Sopenharmony_ci		/* unaligned access */
44862306a36Sopenharmony_ci		u16 tmp;
44962306a36Sopenharmony_ci		tmp = hpi_read_word(dev, addr - 1);
45062306a36Sopenharmony_ci		*buf++ = (tmp >> 8) & 0x00ff;
45162306a36Sopenharmony_ci		addr++;
45262306a36Sopenharmony_ci		len--;
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	hpi_read_words_le16(dev, addr, (__le16 *)buf, len / 2);
45662306a36Sopenharmony_ci	buf += len & ~0x01;
45762306a36Sopenharmony_ci	addr += len & ~0x01;
45862306a36Sopenharmony_ci	len &= 0x01;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	if (len) {
46162306a36Sopenharmony_ci		u16 tmp;
46262306a36Sopenharmony_ci		tmp = hpi_read_word(dev, addr);
46362306a36Sopenharmony_ci		*buf = tmp & 0x00ff;
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_civoid c67x00_ll_init(struct c67x00_device *dev)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	mutex_init(&dev->hpi.lcp.mutex);
47262306a36Sopenharmony_ci	init_completion(&dev->hpi.lcp.msg_received);
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_civoid c67x00_ll_release(struct c67x00_device *dev)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci}
478