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