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