linux/drivers/soc/fsl/qe/qe_tdm.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2015 Freescale Semiconductor, Inc. All rights reserved.
   3 *
   4 * Authors:     Zhao Qiang <qiang.zhao@nxp.com>
   5 *
   6 * Description:
   7 * QE TDM API Set - TDM specific routines implementations.
   8 *
   9 * This program is free software; you can redistribute  it and/or modify it
  10 * under  the terms of  the GNU General  Public License as published by the
  11 * Free Software Foundation;  either version 2 of the  License, or (at your
  12 * option) any later version.
  13 */
  14#include <linux/io.h>
  15#include <linux/kernel.h>
  16#include <linux/of_address.h>
  17#include <linux/of_irq.h>
  18#include <linux/of_platform.h>
  19#include <soc/fsl/qe/qe_tdm.h>
  20
  21static int set_tdm_framer(const char *tdm_framer_type)
  22{
  23        if (strcmp(tdm_framer_type, "e1") == 0)
  24                return TDM_FRAMER_E1;
  25        else if (strcmp(tdm_framer_type, "t1") == 0)
  26                return TDM_FRAMER_T1;
  27        else
  28                return -EINVAL;
  29}
  30
  31static void set_si_param(struct ucc_tdm *utdm, struct ucc_tdm_info *ut_info)
  32{
  33        struct si_mode_info *si_info = &ut_info->si_info;
  34
  35        if (utdm->tdm_mode == TDM_INTERNAL_LOOPBACK) {
  36                si_info->simr_crt = 1;
  37                si_info->simr_rfsd = 0;
  38        }
  39}
  40
  41int ucc_of_parse_tdm(struct device_node *np, struct ucc_tdm *utdm,
  42                     struct ucc_tdm_info *ut_info)
  43{
  44        const char *sprop;
  45        int ret = 0;
  46        u32 val;
  47        struct resource *res;
  48        struct device_node *np2;
  49        static int siram_init_flag;
  50        struct platform_device *pdev;
  51
  52        sprop = of_get_property(np, "fsl,rx-sync-clock", NULL);
  53        if (sprop) {
  54                ut_info->uf_info.rx_sync = qe_clock_source(sprop);
  55                if ((ut_info->uf_info.rx_sync < QE_CLK_NONE) ||
  56                    (ut_info->uf_info.rx_sync > QE_RSYNC_PIN)) {
  57                        pr_err("QE-TDM: Invalid rx-sync-clock property\n");
  58                        return -EINVAL;
  59                }
  60        } else {
  61                pr_err("QE-TDM: Invalid rx-sync-clock property\n");
  62                return -EINVAL;
  63        }
  64
  65        sprop = of_get_property(np, "fsl,tx-sync-clock", NULL);
  66        if (sprop) {
  67                ut_info->uf_info.tx_sync = qe_clock_source(sprop);
  68                if ((ut_info->uf_info.tx_sync < QE_CLK_NONE) ||
  69                    (ut_info->uf_info.tx_sync > QE_TSYNC_PIN)) {
  70                        pr_err("QE-TDM: Invalid tx-sync-clock property\n");
  71                return -EINVAL;
  72                }
  73        } else {
  74                pr_err("QE-TDM: Invalid tx-sync-clock property\n");
  75                return -EINVAL;
  76        }
  77
  78        ret = of_property_read_u32_index(np, "fsl,tx-timeslot-mask", 0, &val);
  79        if (ret) {
  80                pr_err("QE-TDM: Invalid tx-timeslot-mask property\n");
  81                return -EINVAL;
  82        }
  83        utdm->tx_ts_mask = val;
  84
  85        ret = of_property_read_u32_index(np, "fsl,rx-timeslot-mask", 0, &val);
  86        if (ret) {
  87                ret = -EINVAL;
  88                pr_err("QE-TDM: Invalid rx-timeslot-mask property\n");
  89                return ret;
  90        }
  91        utdm->rx_ts_mask = val;
  92
  93        ret = of_property_read_u32_index(np, "fsl,tdm-id", 0, &val);
  94        if (ret) {
  95                ret = -EINVAL;
  96                pr_err("QE-TDM: No fsl,tdm-id property for this UCC\n");
  97                return ret;
  98        }
  99        utdm->tdm_port = val;
 100        ut_info->uf_info.tdm_num = utdm->tdm_port;
 101
 102        if (of_property_read_bool(np, "fsl,tdm-internal-loopback"))
 103                utdm->tdm_mode = TDM_INTERNAL_LOOPBACK;
 104        else
 105                utdm->tdm_mode = TDM_NORMAL;
 106
 107        sprop = of_get_property(np, "fsl,tdm-framer-type", NULL);
 108        if (!sprop) {
 109                ret = -EINVAL;
 110                pr_err("QE-TDM: No tdm-framer-type property for UCC\n");
 111                return ret;
 112        }
 113        ret = set_tdm_framer(sprop);
 114        if (ret < 0)
 115                return -EINVAL;
 116        utdm->tdm_framer_type = ret;
 117
 118        ret = of_property_read_u32_index(np, "fsl,siram-entry-id", 0, &val);
 119        if (ret) {
 120                ret = -EINVAL;
 121                pr_err("QE-TDM: No siram entry id for UCC\n");
 122                return ret;
 123        }
 124        utdm->siram_entry_id = val;
 125
 126        set_si_param(utdm, ut_info);
 127
 128        np2 = of_find_compatible_node(NULL, NULL, "fsl,t1040-qe-si");
 129        if (!np2)
 130                return -EINVAL;
 131
 132        pdev = of_find_device_by_node(np2);
 133        if (!pdev) {
 134                pr_err("%s: failed to lookup pdev\n", np2->name);
 135                of_node_put(np2);
 136                return -EINVAL;
 137        }
 138
 139        of_node_put(np2);
 140        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 141        utdm->si_regs = devm_ioremap_resource(&pdev->dev, res);
 142        if (IS_ERR(utdm->si_regs)) {
 143                ret = PTR_ERR(utdm->si_regs);
 144                goto err_miss_siram_property;
 145        }
 146
 147        np2 = of_find_compatible_node(NULL, NULL, "fsl,t1040-qe-siram");
 148        if (!np2) {
 149                ret = -EINVAL;
 150                goto err_miss_siram_property;
 151        }
 152
 153        pdev = of_find_device_by_node(np2);
 154        if (!pdev) {
 155                ret = -EINVAL;
 156                pr_err("%s: failed to lookup pdev\n", np2->name);
 157                of_node_put(np2);
 158                goto err_miss_siram_property;
 159        }
 160
 161        of_node_put(np2);
 162        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 163        utdm->siram = devm_ioremap_resource(&pdev->dev, res);
 164        if (IS_ERR(utdm->siram)) {
 165                ret = PTR_ERR(utdm->siram);
 166                goto err_miss_siram_property;
 167        }
 168
 169        if (siram_init_flag == 0) {
 170                memset_io(utdm->siram, 0,  resource_size(res));
 171                siram_init_flag = 1;
 172        }
 173
 174        return ret;
 175
 176err_miss_siram_property:
 177        devm_iounmap(&pdev->dev, utdm->si_regs);
 178        return ret;
 179}
 180EXPORT_SYMBOL(ucc_of_parse_tdm);
 181
 182void ucc_tdm_init(struct ucc_tdm *utdm, struct ucc_tdm_info *ut_info)
 183{
 184        struct si1 __iomem *si_regs;
 185        u16 __iomem *siram;
 186        u16 siram_entry_valid;
 187        u16 siram_entry_closed;
 188        u16 ucc_num;
 189        u8 csel;
 190        u16 sixmr;
 191        u16 tdm_port;
 192        u32 siram_entry_id;
 193        u32 mask;
 194        int i;
 195
 196        si_regs = utdm->si_regs;
 197        siram = utdm->siram;
 198        ucc_num = ut_info->uf_info.ucc_num;
 199        tdm_port = utdm->tdm_port;
 200        siram_entry_id = utdm->siram_entry_id;
 201
 202        if (utdm->tdm_framer_type == TDM_FRAMER_T1)
 203                utdm->num_of_ts = 24;
 204        if (utdm->tdm_framer_type == TDM_FRAMER_E1)
 205                utdm->num_of_ts = 32;
 206
 207        /* set siram table */
 208        csel = (ucc_num < 4) ? ucc_num + 9 : ucc_num - 3;
 209
 210        siram_entry_valid = SIR_CSEL(csel) | SIR_BYTE | SIR_CNT(0);
 211        siram_entry_closed = SIR_IDLE | SIR_BYTE | SIR_CNT(0);
 212
 213        for (i = 0; i < utdm->num_of_ts; i++) {
 214                mask = 0x01 << i;
 215
 216                if (utdm->tx_ts_mask & mask)
 217                        iowrite16be(siram_entry_valid,
 218                                    &siram[siram_entry_id * 32 + i]);
 219                else
 220                        iowrite16be(siram_entry_closed,
 221                                    &siram[siram_entry_id * 32 + i]);
 222
 223                if (utdm->rx_ts_mask & mask)
 224                        iowrite16be(siram_entry_valid,
 225                                    &siram[siram_entry_id * 32 + 0x200 +  i]);
 226                else
 227                        iowrite16be(siram_entry_closed,
 228                                    &siram[siram_entry_id * 32 + 0x200 +  i]);
 229        }
 230
 231        setbits16(&siram[(siram_entry_id * 32) + (utdm->num_of_ts - 1)],
 232                  SIR_LAST);
 233        setbits16(&siram[(siram_entry_id * 32) + 0x200 + (utdm->num_of_ts - 1)],
 234                  SIR_LAST);
 235
 236        /* Set SIxMR register */
 237        sixmr = SIMR_SAD(siram_entry_id);
 238
 239        sixmr &= ~SIMR_SDM_MASK;
 240
 241        if (utdm->tdm_mode == TDM_INTERNAL_LOOPBACK)
 242                sixmr |= SIMR_SDM_INTERNAL_LOOPBACK;
 243        else
 244                sixmr |= SIMR_SDM_NORMAL;
 245
 246        sixmr |= SIMR_RFSD(ut_info->si_info.simr_rfsd) |
 247                        SIMR_TFSD(ut_info->si_info.simr_tfsd);
 248
 249        if (ut_info->si_info.simr_crt)
 250                sixmr |= SIMR_CRT;
 251        if (ut_info->si_info.simr_sl)
 252                sixmr |= SIMR_SL;
 253        if (ut_info->si_info.simr_ce)
 254                sixmr |= SIMR_CE;
 255        if (ut_info->si_info.simr_fe)
 256                sixmr |= SIMR_FE;
 257        if (ut_info->si_info.simr_gm)
 258                sixmr |= SIMR_GM;
 259
 260        switch (tdm_port) {
 261        case 0:
 262                iowrite16be(sixmr, &si_regs->sixmr1[0]);
 263                break;
 264        case 1:
 265                iowrite16be(sixmr, &si_regs->sixmr1[1]);
 266                break;
 267        case 2:
 268                iowrite16be(sixmr, &si_regs->sixmr1[2]);
 269                break;
 270        case 3:
 271                iowrite16be(sixmr, &si_regs->sixmr1[3]);
 272                break;
 273        default:
 274                pr_err("QE-TDM: can not find tdm sixmr reg\n");
 275                break;
 276        }
 277}
 278EXPORT_SYMBOL(ucc_tdm_init);
 279