18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * c67x00-ll-hpi.c: Cypress C67X00 USB Low level interface using HPI
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2006-2008 Barco N.V.
68c2ecf20Sopenharmony_ci *    Derived from the Cypress cy7c67200/300 ezusb linux driver and
78c2ecf20Sopenharmony_ci *    based on multiple host controller drivers inside the linux kernel.
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <asm/byteorder.h>
118c2ecf20Sopenharmony_ci#include <linux/delay.h>
128c2ecf20Sopenharmony_ci#include <linux/io.h>
138c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
148c2ecf20Sopenharmony_ci#include <linux/usb/c67x00.h>
158c2ecf20Sopenharmony_ci#include "c67x00.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define COMM_REGS 14
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistruct c67x00_lcp_int_data {
208c2ecf20Sopenharmony_ci	u16 regs[COMM_REGS];
218c2ecf20Sopenharmony_ci};
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- */
248c2ecf20Sopenharmony_ci/* Interface definitions */
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define COMM_ACK			0x0FED
278c2ecf20Sopenharmony_ci#define COMM_NAK			0xDEAD
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define COMM_RESET			0xFA50
308c2ecf20Sopenharmony_ci#define COMM_EXEC_INT			0xCE01
318c2ecf20Sopenharmony_ci#define COMM_INT_NUM			0x01C2
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/* Registers 0 to COMM_REGS-1 */
348c2ecf20Sopenharmony_ci#define COMM_R(x)			(0x01C4 + 2 * (x))
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define HUSB_SIE_pCurrentTDPtr(x)	((x) ? 0x01B2 : 0x01B0)
378c2ecf20Sopenharmony_ci#define HUSB_SIE_pTDListDone_Sem(x)	((x) ? 0x01B8 : 0x01B6)
388c2ecf20Sopenharmony_ci#define HUSB_pEOT			0x01B4
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/* Software interrupts */
418c2ecf20Sopenharmony_ci/* 114, 115: */
428c2ecf20Sopenharmony_ci#define HUSB_SIE_INIT_INT(x)		((x) ? 0x0073 : 0x0072)
438c2ecf20Sopenharmony_ci#define HUSB_RESET_INT			0x0074
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#define SUSB_INIT_INT			0x0071
468c2ecf20Sopenharmony_ci#define SUSB_INIT_INT_LOC		(SUSB_INIT_INT * 2)
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------
498c2ecf20Sopenharmony_ci * HPI implementation
508c2ecf20Sopenharmony_ci *
518c2ecf20Sopenharmony_ci * The c67x00 chip also support control via SPI or HSS serial
528c2ecf20Sopenharmony_ci * interfaces. However, this driver assumes that register access can
538c2ecf20Sopenharmony_ci * be performed from IRQ context. While this is a safe assumption with
548c2ecf20Sopenharmony_ci * the HPI interface, it is not true for the serial interfaces.
558c2ecf20Sopenharmony_ci */
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci/* HPI registers */
588c2ecf20Sopenharmony_ci#define HPI_DATA	0
598c2ecf20Sopenharmony_ci#define HPI_MAILBOX	1
608c2ecf20Sopenharmony_ci#define HPI_ADDR	2
618c2ecf20Sopenharmony_ci#define HPI_STATUS	3
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/*
648c2ecf20Sopenharmony_ci * According to CY7C67300 specification (tables 140 and 141) HPI read and
658c2ecf20Sopenharmony_ci * write cycle duration Tcyc must be at least 6T long, where T is 1/48MHz,
668c2ecf20Sopenharmony_ci * which is 125ns.
678c2ecf20Sopenharmony_ci */
688c2ecf20Sopenharmony_ci#define HPI_T_CYC_NS	125
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic inline u16 hpi_read_reg(struct c67x00_device *dev, int reg)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	ndelay(HPI_T_CYC_NS);
738c2ecf20Sopenharmony_ci	return __raw_readw(dev->hpi.base + reg * dev->hpi.regstep);
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic inline void hpi_write_reg(struct c67x00_device *dev, int reg, u16 value)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	ndelay(HPI_T_CYC_NS);
798c2ecf20Sopenharmony_ci	__raw_writew(value, dev->hpi.base + reg * dev->hpi.regstep);
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic inline u16 hpi_read_word_nolock(struct c67x00_device *dev, u16 reg)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	hpi_write_reg(dev, HPI_ADDR, reg);
858c2ecf20Sopenharmony_ci	return hpi_read_reg(dev, HPI_DATA);
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic u16 hpi_read_word(struct c67x00_device *dev, u16 reg)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	u16 value;
918c2ecf20Sopenharmony_ci	unsigned long flags;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->hpi.lock, flags);
948c2ecf20Sopenharmony_ci	value = hpi_read_word_nolock(dev, reg);
958c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->hpi.lock, flags);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	return value;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic void hpi_write_word_nolock(struct c67x00_device *dev, u16 reg, u16 value)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	hpi_write_reg(dev, HPI_ADDR, reg);
1038c2ecf20Sopenharmony_ci	hpi_write_reg(dev, HPI_DATA, value);
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic void hpi_write_word(struct c67x00_device *dev, u16 reg, u16 value)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	unsigned long flags;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->hpi.lock, flags);
1118c2ecf20Sopenharmony_ci	hpi_write_word_nolock(dev, reg, value);
1128c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->hpi.lock, flags);
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci/*
1168c2ecf20Sopenharmony_ci * Only data is little endian, addr has cpu endianess
1178c2ecf20Sopenharmony_ci */
1188c2ecf20Sopenharmony_cistatic void hpi_write_words_le16(struct c67x00_device *dev, u16 addr,
1198c2ecf20Sopenharmony_ci				 __le16 *data, u16 count)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	unsigned long flags;
1228c2ecf20Sopenharmony_ci	int i;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->hpi.lock, flags);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	hpi_write_reg(dev, HPI_ADDR, addr);
1278c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++)
1288c2ecf20Sopenharmony_ci		hpi_write_reg(dev, HPI_DATA, le16_to_cpu(*data++));
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->hpi.lock, flags);
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci/*
1348c2ecf20Sopenharmony_ci * Only data is little endian, addr has cpu endianess
1358c2ecf20Sopenharmony_ci */
1368c2ecf20Sopenharmony_cistatic void hpi_read_words_le16(struct c67x00_device *dev, u16 addr,
1378c2ecf20Sopenharmony_ci				__le16 *data, u16 count)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	unsigned long flags;
1408c2ecf20Sopenharmony_ci	int i;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->hpi.lock, flags);
1438c2ecf20Sopenharmony_ci	hpi_write_reg(dev, HPI_ADDR, addr);
1448c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++)
1458c2ecf20Sopenharmony_ci		*data++ = cpu_to_le16(hpi_read_reg(dev, HPI_DATA));
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->hpi.lock, flags);
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic void hpi_set_bits(struct c67x00_device *dev, u16 reg, u16 mask)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	u16 value;
1538c2ecf20Sopenharmony_ci	unsigned long flags;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->hpi.lock, flags);
1568c2ecf20Sopenharmony_ci	value = hpi_read_word_nolock(dev, reg);
1578c2ecf20Sopenharmony_ci	hpi_write_word_nolock(dev, reg, value | mask);
1588c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->hpi.lock, flags);
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic void hpi_clear_bits(struct c67x00_device *dev, u16 reg, u16 mask)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	u16 value;
1648c2ecf20Sopenharmony_ci	unsigned long flags;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->hpi.lock, flags);
1678c2ecf20Sopenharmony_ci	value = hpi_read_word_nolock(dev, reg);
1688c2ecf20Sopenharmony_ci	hpi_write_word_nolock(dev, reg, value & ~mask);
1698c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->hpi.lock, flags);
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cistatic u16 hpi_recv_mbox(struct c67x00_device *dev)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	u16 value;
1758c2ecf20Sopenharmony_ci	unsigned long flags;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->hpi.lock, flags);
1788c2ecf20Sopenharmony_ci	value = hpi_read_reg(dev, HPI_MAILBOX);
1798c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->hpi.lock, flags);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	return value;
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic u16 hpi_send_mbox(struct c67x00_device *dev, u16 value)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	unsigned long flags;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->hpi.lock, flags);
1898c2ecf20Sopenharmony_ci	hpi_write_reg(dev, HPI_MAILBOX, value);
1908c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->hpi.lock, flags);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	return value;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ciu16 c67x00_ll_hpi_status(struct c67x00_device *dev)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	u16 value;
1988c2ecf20Sopenharmony_ci	unsigned long flags;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->hpi.lock, flags);
2018c2ecf20Sopenharmony_ci	value = hpi_read_reg(dev, HPI_STATUS);
2028c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->hpi.lock, flags);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	return value;
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_civoid c67x00_ll_hpi_reg_init(struct c67x00_device *dev)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	int i;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	hpi_recv_mbox(dev);
2128c2ecf20Sopenharmony_ci	c67x00_ll_hpi_status(dev);
2138c2ecf20Sopenharmony_ci	hpi_write_word(dev, HPI_IRQ_ROUTING_REG, 0);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	for (i = 0; i < C67X00_SIES; i++) {
2168c2ecf20Sopenharmony_ci		hpi_write_word(dev, SIEMSG_REG(i), 0);
2178c2ecf20Sopenharmony_ci		hpi_read_word(dev, SIEMSG_REG(i));
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_civoid c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG,
2248c2ecf20Sopenharmony_ci		     SOFEOP_TO_HPI_EN(sie->sie_num));
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_civoid c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	hpi_clear_bits(sie->dev, HPI_IRQ_ROUTING_REG,
2308c2ecf20Sopenharmony_ci		       SOFEOP_TO_HPI_EN(sie->sie_num));
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- */
2348c2ecf20Sopenharmony_ci/* Transactions */
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic inline int ll_recv_msg(struct c67x00_device *dev)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	u16 res;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	res = wait_for_completion_timeout(&dev->hpi.lcp.msg_received, 5 * HZ);
2418c2ecf20Sopenharmony_ci	WARN_ON(!res);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	return (res == 0) ? -EIO : 0;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- */
2478c2ecf20Sopenharmony_ci/* General functions */
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ciu16 c67x00_ll_fetch_siemsg(struct c67x00_device *dev, int sie_num)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	u16 val;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	val = hpi_read_word(dev, SIEMSG_REG(sie_num));
2548c2ecf20Sopenharmony_ci	/* clear register to allow next message */
2558c2ecf20Sopenharmony_ci	hpi_write_word(dev, SIEMSG_REG(sie_num), 0);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	return val;
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ciu16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	return hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num));
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci/*
2668c2ecf20Sopenharmony_ci * c67x00_ll_usb_clear_status - clear the USB status bits
2678c2ecf20Sopenharmony_ci */
2688c2ecf20Sopenharmony_civoid c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	hpi_write_word(sie->dev, USB_STAT_REG(sie->sie_num), bits);
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ciu16 c67x00_ll_usb_get_status(struct c67x00_sie *sie)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	return hpi_read_word(sie->dev, USB_STAT_REG(sie->sie_num));
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- */
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_cistatic int c67x00_comm_exec_int(struct c67x00_device *dev, u16 nr,
2818c2ecf20Sopenharmony_ci				struct c67x00_lcp_int_data *data)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	int i, rc;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	mutex_lock(&dev->hpi.lcp.mutex);
2868c2ecf20Sopenharmony_ci	hpi_write_word(dev, COMM_INT_NUM, nr);
2878c2ecf20Sopenharmony_ci	for (i = 0; i < COMM_REGS; i++)
2888c2ecf20Sopenharmony_ci		hpi_write_word(dev, COMM_R(i), data->regs[i]);
2898c2ecf20Sopenharmony_ci	hpi_send_mbox(dev, COMM_EXEC_INT);
2908c2ecf20Sopenharmony_ci	rc = ll_recv_msg(dev);
2918c2ecf20Sopenharmony_ci	mutex_unlock(&dev->hpi.lcp.mutex);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	return rc;
2948c2ecf20Sopenharmony_ci}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- */
2978c2ecf20Sopenharmony_ci/* Host specific functions */
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_civoid c67x00_ll_set_husb_eot(struct c67x00_device *dev, u16 value)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	mutex_lock(&dev->hpi.lcp.mutex);
3028c2ecf20Sopenharmony_ci	hpi_write_word(dev, HUSB_pEOT, value);
3038c2ecf20Sopenharmony_ci	mutex_unlock(&dev->hpi.lcp.mutex);
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic inline void c67x00_ll_husb_sie_init(struct c67x00_sie *sie)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	struct c67x00_device *dev = sie->dev;
3098c2ecf20Sopenharmony_ci	struct c67x00_lcp_int_data data;
3108c2ecf20Sopenharmony_ci	int rc;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	rc = c67x00_comm_exec_int(dev, HUSB_SIE_INIT_INT(sie->sie_num), &data);
3138c2ecf20Sopenharmony_ci	BUG_ON(rc); /* No return path for error code; crash spectacularly */
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_civoid c67x00_ll_husb_reset(struct c67x00_sie *sie, int port)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	struct c67x00_device *dev = sie->dev;
3198c2ecf20Sopenharmony_ci	struct c67x00_lcp_int_data data;
3208c2ecf20Sopenharmony_ci	int rc;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	data.regs[0] = 50;	/* Reset USB port for 50ms */
3238c2ecf20Sopenharmony_ci	data.regs[1] = port | (sie->sie_num << 1);
3248c2ecf20Sopenharmony_ci	rc = c67x00_comm_exec_int(dev, HUSB_RESET_INT, &data);
3258c2ecf20Sopenharmony_ci	BUG_ON(rc); /* No return path for error code; crash spectacularly */
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_civoid c67x00_ll_husb_set_current_td(struct c67x00_sie *sie, u16 addr)
3298c2ecf20Sopenharmony_ci{
3308c2ecf20Sopenharmony_ci	hpi_write_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num), addr);
3318c2ecf20Sopenharmony_ci}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ciu16 c67x00_ll_husb_get_current_td(struct c67x00_sie *sie)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	return hpi_read_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num));
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ciu16 c67x00_ll_husb_get_frame(struct c67x00_sie *sie)
3398c2ecf20Sopenharmony_ci{
3408c2ecf20Sopenharmony_ci	return hpi_read_word(sie->dev, HOST_FRAME_REG(sie->sie_num));
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_civoid c67x00_ll_husb_init_host_port(struct c67x00_sie *sie)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	/* Set port into host mode */
3468c2ecf20Sopenharmony_ci	hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), HOST_MODE);
3478c2ecf20Sopenharmony_ci	c67x00_ll_husb_sie_init(sie);
3488c2ecf20Sopenharmony_ci	/* Clear interrupts */
3498c2ecf20Sopenharmony_ci	c67x00_ll_usb_clear_status(sie, HOST_STAT_MASK);
3508c2ecf20Sopenharmony_ci	/* Check */
3518c2ecf20Sopenharmony_ci	if (!(hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num)) & HOST_MODE))
3528c2ecf20Sopenharmony_ci		dev_warn(sie_dev(sie),
3538c2ecf20Sopenharmony_ci			 "SIE %d not set to host mode\n", sie->sie_num);
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_civoid c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	/* Clear connect change */
3598c2ecf20Sopenharmony_ci	c67x00_ll_usb_clear_status(sie, PORT_CONNECT_CHANGE(port));
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	/* Enable interrupts */
3628c2ecf20Sopenharmony_ci	hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG,
3638c2ecf20Sopenharmony_ci		     SOFEOP_TO_CPU_EN(sie->sie_num));
3648c2ecf20Sopenharmony_ci	hpi_set_bits(sie->dev, HOST_IRQ_EN_REG(sie->sie_num),
3658c2ecf20Sopenharmony_ci		     SOF_EOP_IRQ_EN | DONE_IRQ_EN);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	/* Enable pull down transistors */
3688c2ecf20Sopenharmony_ci	hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), PORT_RES_EN(port));
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- */
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_civoid c67x00_ll_irq(struct c67x00_device *dev, u16 int_status)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	if ((int_status & MBX_OUT_FLG) == 0)
3768c2ecf20Sopenharmony_ci		return;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	dev->hpi.lcp.last_msg = hpi_recv_mbox(dev);
3798c2ecf20Sopenharmony_ci	complete(&dev->hpi.lcp.msg_received);
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- */
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ciint c67x00_ll_reset(struct c67x00_device *dev)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	int rc;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	mutex_lock(&dev->hpi.lcp.mutex);
3898c2ecf20Sopenharmony_ci	hpi_send_mbox(dev, COMM_RESET);
3908c2ecf20Sopenharmony_ci	rc = ll_recv_msg(dev);
3918c2ecf20Sopenharmony_ci	mutex_unlock(&dev->hpi.lcp.mutex);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	return rc;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- */
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci/*
3998c2ecf20Sopenharmony_ci * c67x00_ll_write_mem_le16 - write into c67x00 memory
4008c2ecf20Sopenharmony_ci * Only data is little endian, addr has cpu endianess.
4018c2ecf20Sopenharmony_ci */
4028c2ecf20Sopenharmony_civoid c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr,
4038c2ecf20Sopenharmony_ci			      void *data, int len)
4048c2ecf20Sopenharmony_ci{
4058c2ecf20Sopenharmony_ci	u8 *buf = data;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	/* Sanity check */
4088c2ecf20Sopenharmony_ci	if (addr + len > 0xffff) {
4098c2ecf20Sopenharmony_ci		dev_err(&dev->pdev->dev,
4108c2ecf20Sopenharmony_ci			"Trying to write beyond writable region!\n");
4118c2ecf20Sopenharmony_ci		return;
4128c2ecf20Sopenharmony_ci	}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	if (addr & 0x01) {
4158c2ecf20Sopenharmony_ci		/* unaligned access */
4168c2ecf20Sopenharmony_ci		u16 tmp;
4178c2ecf20Sopenharmony_ci		tmp = hpi_read_word(dev, addr - 1);
4188c2ecf20Sopenharmony_ci		tmp = (tmp & 0x00ff) | (*buf++ << 8);
4198c2ecf20Sopenharmony_ci		hpi_write_word(dev, addr - 1, tmp);
4208c2ecf20Sopenharmony_ci		addr++;
4218c2ecf20Sopenharmony_ci		len--;
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	hpi_write_words_le16(dev, addr, (__le16 *)buf, len / 2);
4258c2ecf20Sopenharmony_ci	buf += len & ~0x01;
4268c2ecf20Sopenharmony_ci	addr += len & ~0x01;
4278c2ecf20Sopenharmony_ci	len &= 0x01;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	if (len) {
4308c2ecf20Sopenharmony_ci		u16 tmp;
4318c2ecf20Sopenharmony_ci		tmp = hpi_read_word(dev, addr);
4328c2ecf20Sopenharmony_ci		tmp = (tmp & 0xff00) | *buf;
4338c2ecf20Sopenharmony_ci		hpi_write_word(dev, addr, tmp);
4348c2ecf20Sopenharmony_ci	}
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci/*
4388c2ecf20Sopenharmony_ci * c67x00_ll_read_mem_le16 - read from c67x00 memory
4398c2ecf20Sopenharmony_ci * Only data is little endian, addr has cpu endianess.
4408c2ecf20Sopenharmony_ci */
4418c2ecf20Sopenharmony_civoid c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr,
4428c2ecf20Sopenharmony_ci			     void *data, int len)
4438c2ecf20Sopenharmony_ci{
4448c2ecf20Sopenharmony_ci	u8 *buf = data;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	if (addr & 0x01) {
4478c2ecf20Sopenharmony_ci		/* unaligned access */
4488c2ecf20Sopenharmony_ci		u16 tmp;
4498c2ecf20Sopenharmony_ci		tmp = hpi_read_word(dev, addr - 1);
4508c2ecf20Sopenharmony_ci		*buf++ = (tmp >> 8) & 0x00ff;
4518c2ecf20Sopenharmony_ci		addr++;
4528c2ecf20Sopenharmony_ci		len--;
4538c2ecf20Sopenharmony_ci	}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	hpi_read_words_le16(dev, addr, (__le16 *)buf, len / 2);
4568c2ecf20Sopenharmony_ci	buf += len & ~0x01;
4578c2ecf20Sopenharmony_ci	addr += len & ~0x01;
4588c2ecf20Sopenharmony_ci	len &= 0x01;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	if (len) {
4618c2ecf20Sopenharmony_ci		u16 tmp;
4628c2ecf20Sopenharmony_ci		tmp = hpi_read_word(dev, addr);
4638c2ecf20Sopenharmony_ci		*buf = tmp & 0x00ff;
4648c2ecf20Sopenharmony_ci	}
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- */
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_civoid c67x00_ll_init(struct c67x00_device *dev)
4708c2ecf20Sopenharmony_ci{
4718c2ecf20Sopenharmony_ci	mutex_init(&dev->hpi.lcp.mutex);
4728c2ecf20Sopenharmony_ci	init_completion(&dev->hpi.lcp.msg_received);
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_civoid c67x00_ll_release(struct c67x00_device *dev)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci}
478