linux/drivers/media/video/blackfin/ppi.c
<<
>>
Prefs
   1/*
   2 * ppi.c Analog Devices Parallel Peripheral Interface driver
   3 *
   4 * Copyright (c) 2011 Analog Devices Inc.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18 */
  19
  20#include <linux/slab.h>
  21
  22#include <asm/bfin_ppi.h>
  23#include <asm/blackfin.h>
  24#include <asm/cacheflush.h>
  25#include <asm/dma.h>
  26#include <asm/portmux.h>
  27
  28#include <media/blackfin/ppi.h>
  29
  30static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler);
  31static void ppi_detach_irq(struct ppi_if *ppi);
  32static int ppi_start(struct ppi_if *ppi);
  33static int ppi_stop(struct ppi_if *ppi);
  34static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params);
  35static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr);
  36
  37static const struct ppi_ops ppi_ops = {
  38        .attach_irq = ppi_attach_irq,
  39        .detach_irq = ppi_detach_irq,
  40        .start = ppi_start,
  41        .stop = ppi_stop,
  42        .set_params = ppi_set_params,
  43        .update_addr = ppi_update_addr,
  44};
  45
  46static irqreturn_t ppi_irq_err(int irq, void *dev_id)
  47{
  48        struct ppi_if *ppi = dev_id;
  49        const struct ppi_info *info = ppi->info;
  50
  51        switch (info->type) {
  52        case PPI_TYPE_PPI:
  53        {
  54                struct bfin_ppi_regs *reg = info->base;
  55                unsigned short status;
  56
  57                /* register on bf561 is cleared when read 
  58                 * others are W1C
  59                 */
  60                status = bfin_read16(&reg->status);
  61                bfin_write16(&reg->status, 0xff00);
  62                break;
  63        }
  64        case PPI_TYPE_EPPI:
  65        {
  66                struct bfin_eppi_regs *reg = info->base;
  67                bfin_write16(&reg->status, 0xffff);
  68                break;
  69        }
  70        default:
  71                break;
  72        }
  73
  74        return IRQ_HANDLED;
  75}
  76
  77static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler)
  78{
  79        const struct ppi_info *info = ppi->info;
  80        int ret;
  81
  82        ret = request_dma(info->dma_ch, "PPI_DMA");
  83
  84        if (ret) {
  85                pr_err("Unable to allocate DMA channel for PPI\n");
  86                return ret;
  87        }
  88        set_dma_callback(info->dma_ch, handler, ppi);
  89
  90        if (ppi->err_int) {
  91                ret = request_irq(info->irq_err, ppi_irq_err, 0, "PPI ERROR", ppi);
  92                if (ret) {
  93                        pr_err("Unable to allocate IRQ for PPI\n");
  94                        free_dma(info->dma_ch);
  95                }
  96        }
  97        return ret;
  98}
  99
 100static void ppi_detach_irq(struct ppi_if *ppi)
 101{
 102        const struct ppi_info *info = ppi->info;
 103
 104        if (ppi->err_int)
 105                free_irq(info->irq_err, ppi);
 106        free_dma(info->dma_ch);
 107}
 108
 109static int ppi_start(struct ppi_if *ppi)
 110{
 111        const struct ppi_info *info = ppi->info;
 112
 113        /* enable DMA */
 114        enable_dma(info->dma_ch);
 115
 116        /* enable PPI */
 117        ppi->ppi_control |= PORT_EN;
 118        switch (info->type) {
 119        case PPI_TYPE_PPI:
 120        {
 121                struct bfin_ppi_regs *reg = info->base;
 122                bfin_write16(&reg->control, ppi->ppi_control);
 123                break;
 124        }
 125        case PPI_TYPE_EPPI:
 126        {
 127                struct bfin_eppi_regs *reg = info->base;
 128                bfin_write32(&reg->control, ppi->ppi_control);
 129                break;
 130        }
 131        default:
 132                return -EINVAL;
 133        }
 134
 135        SSYNC();
 136        return 0;
 137}
 138
 139static int ppi_stop(struct ppi_if *ppi)
 140{
 141        const struct ppi_info *info = ppi->info;
 142
 143        /* disable PPI */
 144        ppi->ppi_control &= ~PORT_EN;
 145        switch (info->type) {
 146        case PPI_TYPE_PPI:
 147        {
 148                struct bfin_ppi_regs *reg = info->base;
 149                bfin_write16(&reg->control, ppi->ppi_control);
 150                break;
 151        }
 152        case PPI_TYPE_EPPI:
 153        {
 154                struct bfin_eppi_regs *reg = info->base;
 155                bfin_write32(&reg->control, ppi->ppi_control);
 156                break;
 157        }
 158        default:
 159                return -EINVAL;
 160        }
 161
 162        /* disable DMA */
 163        clear_dma_irqstat(info->dma_ch);
 164        disable_dma(info->dma_ch);
 165
 166        SSYNC();
 167        return 0;
 168}
 169
 170static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params)
 171{
 172        const struct ppi_info *info = ppi->info;
 173        int dma32 = 0;
 174        int dma_config, bytes_per_line, lines_per_frame;
 175
 176        bytes_per_line = params->width * params->bpp / 8;
 177        lines_per_frame = params->height;
 178        if (params->int_mask == 0xFFFFFFFF)
 179                ppi->err_int = false;
 180        else
 181                ppi->err_int = true;
 182
 183        dma_config = (DMA_FLOW_STOP | WNR | RESTART | DMA2D | DI_EN);
 184        ppi->ppi_control = params->ppi_control & ~PORT_EN;
 185        switch (info->type) {
 186        case PPI_TYPE_PPI:
 187        {
 188                struct bfin_ppi_regs *reg = info->base;
 189
 190                if (params->ppi_control & DMA32)
 191                        dma32 = 1;
 192
 193                bfin_write16(&reg->control, ppi->ppi_control);
 194                bfin_write16(&reg->count, bytes_per_line - 1);
 195                bfin_write16(&reg->frame, lines_per_frame);
 196                break;
 197        }
 198        case PPI_TYPE_EPPI:
 199        {
 200                struct bfin_eppi_regs *reg = info->base;
 201
 202                if ((params->ppi_control & PACK_EN)
 203                        || (params->ppi_control & 0x38000) > DLEN_16)
 204                        dma32 = 1;
 205
 206                bfin_write32(&reg->control, ppi->ppi_control);
 207                bfin_write16(&reg->line, bytes_per_line + params->blank_clocks);
 208                bfin_write16(&reg->frame, lines_per_frame);
 209                bfin_write16(&reg->hdelay, 0);
 210                bfin_write16(&reg->vdelay, 0);
 211                bfin_write16(&reg->hcount, bytes_per_line);
 212                bfin_write16(&reg->vcount, lines_per_frame);
 213                break;
 214        }
 215        default:
 216                return -EINVAL;
 217        }
 218
 219        if (dma32) {
 220                dma_config |= WDSIZE_32;
 221                set_dma_x_count(info->dma_ch, bytes_per_line >> 2);
 222                set_dma_x_modify(info->dma_ch, 4);
 223                set_dma_y_modify(info->dma_ch, 4);
 224        } else {
 225                dma_config |= WDSIZE_16;
 226                set_dma_x_count(info->dma_ch, bytes_per_line >> 1);
 227                set_dma_x_modify(info->dma_ch, 2);
 228                set_dma_y_modify(info->dma_ch, 2);
 229        }
 230        set_dma_y_count(info->dma_ch, lines_per_frame);
 231        set_dma_config(info->dma_ch, dma_config);
 232
 233        SSYNC();
 234        return 0;
 235}
 236
 237static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr)
 238{
 239        set_dma_start_addr(ppi->info->dma_ch, addr);
 240}
 241
 242struct ppi_if *ppi_create_instance(const struct ppi_info *info)
 243{
 244        struct ppi_if *ppi;
 245
 246        if (!info || !info->pin_req)
 247                return NULL;
 248
 249        if (peripheral_request_list(info->pin_req, KBUILD_MODNAME)) {
 250                pr_err("request peripheral failed\n");
 251                return NULL;
 252        }
 253
 254        ppi = kzalloc(sizeof(*ppi), GFP_KERNEL);
 255        if (!ppi) {
 256                peripheral_free_list(info->pin_req);
 257                pr_err("unable to allocate memory for ppi handle\n");
 258                return NULL;
 259        }
 260        ppi->ops = &ppi_ops;
 261        ppi->info = info;
 262
 263        pr_info("ppi probe success\n");
 264        return ppi;
 265}
 266
 267void ppi_delete_instance(struct ppi_if *ppi)
 268{
 269        peripheral_free_list(ppi->info->pin_req);
 270        kfree(ppi);
 271}
 272