linux/drivers/mfd/ti-ssp.c
<<
>>
Prefs
   1/*
   2 * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs
   3 *
   4 * Copyright (C) 2010 Texas Instruments 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 as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program; if not, write to the Free Software
  18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19 */
  20
  21#include <linux/errno.h>
  22#include <linux/kernel.h>
  23#include <linux/module.h>
  24#include <linux/slab.h>
  25#include <linux/err.h>
  26#include <linux/init.h>
  27#include <linux/wait.h>
  28#include <linux/clk.h>
  29#include <linux/interrupt.h>
  30#include <linux/device.h>
  31#include <linux/spinlock.h>
  32#include <linux/platform_device.h>
  33#include <linux/delay.h>
  34#include <linux/io.h>
  35#include <linux/mfd/core.h>
  36#include <linux/mfd/ti_ssp.h>
  37
  38/* Register Offsets */
  39#define REG_REV         0x00
  40#define REG_IOSEL_1     0x04
  41#define REG_IOSEL_2     0x08
  42#define REG_PREDIV      0x0c
  43#define REG_INTR_ST     0x10
  44#define REG_INTR_EN     0x14
  45#define REG_TEST_CTRL   0x18
  46
  47/* Per port registers */
  48#define PORT_CFG_2      0x00
  49#define PORT_ADDR       0x04
  50#define PORT_DATA       0x08
  51#define PORT_CFG_1      0x0c
  52#define PORT_STATE      0x10
  53
  54#define SSP_PORT_CONFIG_MASK    (SSP_EARLY_DIN | SSP_DELAY_DOUT)
  55#define SSP_PORT_CLKRATE_MASK   0x0f
  56
  57#define SSP_SEQRAM_WR_EN        BIT(4)
  58#define SSP_SEQRAM_RD_EN        BIT(5)
  59#define SSP_START               BIT(15)
  60#define SSP_BUSY                BIT(10)
  61#define SSP_PORT_ASL            BIT(7)
  62#define SSP_PORT_CFO1           BIT(6)
  63
  64#define SSP_PORT_SEQRAM_SIZE    32
  65
  66static const int ssp_port_base[]   = {0x040, 0x080};
  67static const int ssp_port_seqram[] = {0x100, 0x180};
  68
  69struct ti_ssp {
  70        struct resource         *res;
  71        struct device           *dev;
  72        void __iomem            *regs;
  73        spinlock_t              lock;
  74        struct clk              *clk;
  75        int                     irq;
  76        wait_queue_head_t       wqh;
  77
  78        /*
  79         * Some of the iosel2 register bits always read-back as 0, we need to
  80         * remember these values so that we don't clobber previously set
  81         * values.
  82         */
  83        u32                     iosel2;
  84};
  85
  86static inline struct ti_ssp *dev_to_ssp(struct device *dev)
  87{
  88        return dev_get_drvdata(dev->parent);
  89}
  90
  91static inline int dev_to_port(struct device *dev)
  92{
  93        return to_platform_device(dev)->id;
  94}
  95
  96/* Register Access Helpers, rmw() functions need to run locked */
  97static inline u32 ssp_read(struct ti_ssp *ssp, int reg)
  98{
  99        return __raw_readl(ssp->regs + reg);
 100}
 101
 102static inline void ssp_write(struct ti_ssp *ssp, int reg, u32 val)
 103{
 104        __raw_writel(val, ssp->regs + reg);
 105}
 106
 107static inline void ssp_rmw(struct ti_ssp *ssp, int reg, u32 mask, u32 bits)
 108{
 109        ssp_write(ssp, reg, (ssp_read(ssp, reg) & ~mask) | bits);
 110}
 111
 112static inline u32 ssp_port_read(struct ti_ssp *ssp, int port, int reg)
 113{
 114        return ssp_read(ssp, ssp_port_base[port] + reg);
 115}
 116
 117static inline void ssp_port_write(struct ti_ssp *ssp, int port, int reg,
 118                                  u32 val)
 119{
 120        ssp_write(ssp, ssp_port_base[port] + reg, val);
 121}
 122
 123static inline void ssp_port_rmw(struct ti_ssp *ssp, int port, int reg,
 124                                u32 mask, u32 bits)
 125{
 126        ssp_rmw(ssp, ssp_port_base[port] + reg, mask, bits);
 127}
 128
 129static inline void ssp_port_clr_bits(struct ti_ssp *ssp, int port, int reg,
 130                                     u32 bits)
 131{
 132        ssp_port_rmw(ssp, port, reg, bits, 0);
 133}
 134
 135static inline void ssp_port_set_bits(struct ti_ssp *ssp, int port, int reg,
 136                                     u32 bits)
 137{
 138        ssp_port_rmw(ssp, port, reg, 0, bits);
 139}
 140
 141/* Called to setup port clock mode, caller must hold ssp->lock */
 142static int __set_mode(struct ti_ssp *ssp, int port, int mode)
 143{
 144        mode &= SSP_PORT_CONFIG_MASK;
 145        ssp_port_rmw(ssp, port, PORT_CFG_1, SSP_PORT_CONFIG_MASK, mode);
 146
 147        return 0;
 148}
 149
 150int ti_ssp_set_mode(struct device *dev, int mode)
 151{
 152        struct ti_ssp *ssp = dev_to_ssp(dev);
 153        int port = dev_to_port(dev);
 154        int ret;
 155
 156        spin_lock(&ssp->lock);
 157        ret = __set_mode(ssp, port, mode);
 158        spin_unlock(&ssp->lock);
 159
 160        return ret;
 161}
 162EXPORT_SYMBOL(ti_ssp_set_mode);
 163
 164/* Called to setup iosel2, caller must hold ssp->lock */
 165static void __set_iosel2(struct ti_ssp *ssp, u32 mask, u32 val)
 166{
 167        ssp->iosel2 = (ssp->iosel2 & ~mask) | val;
 168        ssp_write(ssp, REG_IOSEL_2, ssp->iosel2);
 169}
 170
 171/* Called to setup port iosel, caller must hold ssp->lock */
 172static void __set_iosel(struct ti_ssp *ssp, int port, u32 iosel)
 173{
 174        unsigned val, shift = port ? 16 : 0;
 175
 176        /* IOSEL1 gets the least significant 16 bits */
 177        val = ssp_read(ssp, REG_IOSEL_1);
 178        val &= 0xffff << (port ? 0 : 16);
 179        val |= (iosel & 0xffff) << (port ? 16 : 0);
 180        ssp_write(ssp, REG_IOSEL_1, val);
 181
 182        /* IOSEL2 gets the most significant 16 bits */
 183        val = (iosel >> 16) & 0x7;
 184        __set_iosel2(ssp, 0x7 << shift, val << shift);
 185}
 186
 187int ti_ssp_set_iosel(struct device *dev, u32 iosel)
 188{
 189        struct ti_ssp *ssp = dev_to_ssp(dev);
 190        int port = dev_to_port(dev);
 191
 192        spin_lock(&ssp->lock);
 193        __set_iosel(ssp, port, iosel);
 194        spin_unlock(&ssp->lock);
 195
 196        return 0;
 197}
 198EXPORT_SYMBOL(ti_ssp_set_iosel);
 199
 200int ti_ssp_load(struct device *dev, int offs, u32* prog, int len)
 201{
 202        struct ti_ssp *ssp = dev_to_ssp(dev);
 203        int port = dev_to_port(dev);
 204        int i;
 205
 206        if (len > SSP_PORT_SEQRAM_SIZE)
 207                return -ENOSPC;
 208
 209        spin_lock(&ssp->lock);
 210
 211        /* Enable SeqRAM access */
 212        ssp_port_set_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN);
 213
 214        /* Copy code */
 215        for (i = 0; i < len; i++) {
 216                __raw_writel(prog[i], ssp->regs + offs + 4*i +
 217                             ssp_port_seqram[port]);
 218        }
 219
 220        /* Disable SeqRAM access */
 221        ssp_port_clr_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN);
 222
 223        spin_unlock(&ssp->lock);
 224
 225        return 0;
 226}
 227EXPORT_SYMBOL(ti_ssp_load);
 228
 229int ti_ssp_raw_read(struct device *dev)
 230{
 231        struct ti_ssp *ssp = dev_to_ssp(dev);
 232        int port = dev_to_port(dev);
 233        int shift = port ? 27 : 11;
 234
 235        return (ssp_read(ssp, REG_IOSEL_2) >> shift) & 0xf;
 236}
 237EXPORT_SYMBOL(ti_ssp_raw_read);
 238
 239int ti_ssp_raw_write(struct device *dev, u32 val)
 240{
 241        struct ti_ssp *ssp = dev_to_ssp(dev);
 242        int port = dev_to_port(dev), shift;
 243
 244        spin_lock(&ssp->lock);
 245
 246        shift = port ? 22 : 6;
 247        val &= 0xf;
 248        __set_iosel2(ssp, 0xf << shift, val << shift);
 249
 250        spin_unlock(&ssp->lock);
 251
 252        return 0;
 253}
 254EXPORT_SYMBOL(ti_ssp_raw_write);
 255
 256static inline int __xfer_done(struct ti_ssp *ssp, int port)
 257{
 258        return !(ssp_port_read(ssp, port, PORT_CFG_1) & SSP_BUSY);
 259}
 260
 261int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output)
 262{
 263        struct ti_ssp *ssp = dev_to_ssp(dev);
 264        int port = dev_to_port(dev);
 265        int ret;
 266
 267        if (pc & ~(0x3f))
 268                return -EINVAL;
 269
 270        /* Grab ssp->lock to serialize rmw on ssp registers */
 271        spin_lock(&ssp->lock);
 272
 273        ssp_port_write(ssp, port, PORT_ADDR, input >> 16);
 274        ssp_port_write(ssp, port, PORT_DATA, input & 0xffff);
 275        ssp_port_rmw(ssp, port, PORT_CFG_1, 0x3f, pc);
 276
 277        /* grab wait queue head lock to avoid race with the isr */
 278        spin_lock_irq(&ssp->wqh.lock);
 279
 280        /* kick off sequence execution in hardware */
 281        ssp_port_set_bits(ssp, port, PORT_CFG_1, SSP_START);
 282
 283        /* drop ssp lock; no register writes beyond this */
 284        spin_unlock(&ssp->lock);
 285
 286        ret = wait_event_interruptible_locked_irq(ssp->wqh,
 287                                                  __xfer_done(ssp, port));
 288        spin_unlock_irq(&ssp->wqh.lock);
 289
 290        if (ret < 0)
 291                return ret;
 292
 293        if (output) {
 294                *output = (ssp_port_read(ssp, port, PORT_ADDR) << 16) |
 295                          (ssp_port_read(ssp, port, PORT_DATA) &  0xffff);
 296        }
 297
 298        ret = ssp_port_read(ssp, port, PORT_STATE) & 0x3f; /* stop address */
 299
 300        return ret;
 301}
 302EXPORT_SYMBOL(ti_ssp_run);
 303
 304static irqreturn_t ti_ssp_interrupt(int irq, void *dev_data)
 305{
 306        struct ti_ssp *ssp = dev_data;
 307
 308        spin_lock(&ssp->wqh.lock);
 309
 310        ssp_write(ssp, REG_INTR_ST, 0x3);
 311        wake_up_locked(&ssp->wqh);
 312
 313        spin_unlock(&ssp->wqh.lock);
 314
 315        return IRQ_HANDLED;
 316}
 317
 318static int __devinit ti_ssp_probe(struct platform_device *pdev)
 319{
 320        static struct ti_ssp *ssp;
 321        const struct ti_ssp_data *pdata = pdev->dev.platform_data;
 322        int error = 0, prediv = 0xff, id;
 323        unsigned long sysclk;
 324        struct device *dev = &pdev->dev;
 325        struct mfd_cell cells[2];
 326
 327        ssp = kzalloc(sizeof(*ssp), GFP_KERNEL);
 328        if (!ssp) {
 329                dev_err(dev, "cannot allocate device info\n");
 330                return -ENOMEM;
 331        }
 332
 333        ssp->dev = dev;
 334        dev_set_drvdata(dev, ssp);
 335
 336        ssp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 337        if (!ssp->res) {
 338                error = -ENODEV;
 339                dev_err(dev, "cannot determine register area\n");
 340                goto error_res;
 341        }
 342
 343        if (!request_mem_region(ssp->res->start, resource_size(ssp->res),
 344                                pdev->name)) {
 345                error = -ENOMEM;
 346                dev_err(dev, "cannot claim register memory\n");
 347                goto error_res;
 348        }
 349
 350        ssp->regs = ioremap(ssp->res->start, resource_size(ssp->res));
 351        if (!ssp->regs) {
 352                error = -ENOMEM;
 353                dev_err(dev, "cannot map register memory\n");
 354                goto error_map;
 355        }
 356
 357        ssp->clk = clk_get(dev, NULL);
 358        if (IS_ERR(ssp->clk)) {
 359                error = PTR_ERR(ssp->clk);
 360                dev_err(dev, "cannot claim device clock\n");
 361                goto error_clk;
 362        }
 363
 364        ssp->irq = platform_get_irq(pdev, 0);
 365        if (ssp->irq < 0) {
 366                error = -ENODEV;
 367                dev_err(dev, "unknown irq\n");
 368                goto error_irq;
 369        }
 370
 371        error = request_threaded_irq(ssp->irq, NULL, ti_ssp_interrupt, 0,
 372                                     dev_name(dev), ssp);
 373        if (error < 0) {
 374                dev_err(dev, "cannot acquire irq\n");
 375                goto error_irq;
 376        }
 377
 378        spin_lock_init(&ssp->lock);
 379        init_waitqueue_head(&ssp->wqh);
 380
 381        /* Power on and initialize SSP */
 382        error = clk_enable(ssp->clk);
 383        if (error) {
 384                dev_err(dev, "cannot enable device clock\n");
 385                goto error_enable;
 386        }
 387
 388        /* Reset registers to a sensible known state */
 389        ssp_write(ssp, REG_IOSEL_1, 0);
 390        ssp_write(ssp, REG_IOSEL_2, 0);
 391        ssp_write(ssp, REG_INTR_EN, 0x3);
 392        ssp_write(ssp, REG_INTR_ST, 0x3);
 393        ssp_write(ssp, REG_TEST_CTRL, 0);
 394        ssp_port_write(ssp, 0, PORT_CFG_1, SSP_PORT_ASL);
 395        ssp_port_write(ssp, 1, PORT_CFG_1, SSP_PORT_ASL);
 396        ssp_port_write(ssp, 0, PORT_CFG_2, SSP_PORT_CFO1);
 397        ssp_port_write(ssp, 1, PORT_CFG_2, SSP_PORT_CFO1);
 398
 399        sysclk = clk_get_rate(ssp->clk);
 400        if (pdata && pdata->out_clock)
 401                prediv = (sysclk / pdata->out_clock) - 1;
 402        prediv = clamp(prediv, 0, 0xff);
 403        ssp_rmw(ssp, REG_PREDIV, 0xff, prediv);
 404
 405        memset(cells, 0, sizeof(cells));
 406        for (id = 0; id < 2; id++) {
 407                const struct ti_ssp_dev_data *data = &pdata->dev_data[id];
 408
 409                cells[id].id            = id;
 410                cells[id].name          = data->dev_name;
 411                cells[id].platform_data = data->pdata;
 412                cells[id].data_size     = data->pdata_size;
 413        }
 414
 415        error = mfd_add_devices(dev, 0, cells, 2, NULL, 0, NULL);
 416        if (error < 0) {
 417                dev_err(dev, "cannot add mfd cells\n");
 418                goto error_enable;
 419        }
 420
 421        return 0;
 422
 423error_enable:
 424        free_irq(ssp->irq, ssp);
 425error_irq:
 426        clk_put(ssp->clk);
 427error_clk:
 428        iounmap(ssp->regs);
 429error_map:
 430        release_mem_region(ssp->res->start, resource_size(ssp->res));
 431error_res:
 432        kfree(ssp);
 433        return error;
 434}
 435
 436static int __devexit ti_ssp_remove(struct platform_device *pdev)
 437{
 438        struct device *dev = &pdev->dev;
 439        struct ti_ssp *ssp = dev_get_drvdata(dev);
 440
 441        mfd_remove_devices(dev);
 442        clk_disable(ssp->clk);
 443        free_irq(ssp->irq, ssp);
 444        clk_put(ssp->clk);
 445        iounmap(ssp->regs);
 446        release_mem_region(ssp->res->start, resource_size(ssp->res));
 447        kfree(ssp);
 448        dev_set_drvdata(dev, NULL);
 449        return 0;
 450}
 451
 452static struct platform_driver ti_ssp_driver = {
 453        .probe          = ti_ssp_probe,
 454        .remove         = __devexit_p(ti_ssp_remove),
 455        .driver         = {
 456                .name   = "ti-ssp",
 457                .owner  = THIS_MODULE,
 458        }
 459};
 460
 461module_platform_driver(ti_ssp_driver);
 462
 463MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver");
 464MODULE_AUTHOR("Cyril Chemparathy");
 465MODULE_LICENSE("GPL");
 466MODULE_ALIAS("platform:ti-ssp");
 467
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.