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