linux/sound/soc/sh/rcar/gen.c
<<
>>
Prefs
   1/*
   2 * Renesas R-Car Gen1 SRU/SSI support
   3 *
   4 * Copyright (C) 2013 Renesas Solutions Corp.
   5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 */
  11
  12/*
  13 * #define DEBUG
  14 *
  15 * you can also add below in
  16 * ${LINUX}/drivers/base/regmap/regmap.c
  17 * for regmap debug
  18 *
  19 * #define LOG_DEVICE "xxxx.rcar_sound"
  20 */
  21
  22#include "rsnd.h"
  23
  24struct rsnd_gen {
  25        struct rsnd_gen_ops *ops;
  26
  27        /* RSND_BASE_MAX base */
  28        void __iomem *base[RSND_BASE_MAX];
  29        phys_addr_t res[RSND_BASE_MAX];
  30        struct regmap *regmap[RSND_BASE_MAX];
  31
  32        /* RSND_REG_MAX base */
  33        struct regmap_field *regs[RSND_REG_MAX];
  34        const char *reg_name[RSND_REG_MAX];
  35};
  36
  37#define rsnd_priv_to_gen(p)     ((struct rsnd_gen *)(p)->gen)
  38#define rsnd_reg_name(gen, id)  ((gen)->reg_name[id])
  39
  40struct rsnd_regmap_field_conf {
  41        int idx;
  42        unsigned int reg_offset;
  43        unsigned int id_offset;
  44        const char *reg_name;
  45};
  46
  47#define RSND_REG_SET(id, offset, _id_offset, n) \
  48{                                               \
  49        .idx = id,                              \
  50        .reg_offset = offset,                   \
  51        .id_offset = _id_offset,                \
  52        .reg_name = n,                          \
  53}
  54/* single address mapping */
  55#define RSND_GEN_S_REG(id, offset)      \
  56        RSND_REG_SET(RSND_REG_##id, offset, 0, #id)
  57
  58/* multi address mapping */
  59#define RSND_GEN_M_REG(id, offset, _id_offset)  \
  60        RSND_REG_SET(RSND_REG_##id, offset, _id_offset, #id)
  61
  62/*
  63 *              basic function
  64 */
  65static int rsnd_is_accessible_reg(struct rsnd_priv *priv,
  66                                  struct rsnd_gen *gen, enum rsnd_reg reg)
  67{
  68        if (!gen->regs[reg]) {
  69                struct device *dev = rsnd_priv_to_dev(priv);
  70
  71                dev_err(dev, "unsupported register access %x\n", reg);
  72                return 0;
  73        }
  74
  75        return 1;
  76}
  77
  78u32 rsnd_read(struct rsnd_priv *priv,
  79              struct rsnd_mod *mod, enum rsnd_reg reg)
  80{
  81        struct device *dev = rsnd_priv_to_dev(priv);
  82        struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
  83        u32 val;
  84
  85        if (!rsnd_is_accessible_reg(priv, gen, reg))
  86                return 0;
  87
  88        regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val);
  89
  90        dev_dbg(dev, "r %s[%d] - %-18s (%4d) : %08x\n",
  91                rsnd_mod_name(mod), rsnd_mod_id(mod),
  92                rsnd_reg_name(gen, reg), reg, val);
  93
  94        return val;
  95}
  96
  97void rsnd_write(struct rsnd_priv *priv,
  98                struct rsnd_mod *mod,
  99                enum rsnd_reg reg, u32 data)
 100{
 101        struct device *dev = rsnd_priv_to_dev(priv);
 102        struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
 103
 104        if (!rsnd_is_accessible_reg(priv, gen, reg))
 105                return;
 106
 107        regmap_fields_force_write(gen->regs[reg], rsnd_mod_id(mod), data);
 108
 109        dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n",
 110                rsnd_mod_name(mod), rsnd_mod_id(mod),
 111                rsnd_reg_name(gen, reg), reg, data);
 112}
 113
 114void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
 115               enum rsnd_reg reg, u32 mask, u32 data)
 116{
 117        struct device *dev = rsnd_priv_to_dev(priv);
 118        struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
 119
 120        if (!rsnd_is_accessible_reg(priv, gen, reg))
 121                return;
 122
 123        regmap_fields_force_update_bits(gen->regs[reg],
 124                                        rsnd_mod_id(mod), mask, data);
 125
 126        dev_dbg(dev, "b %s[%d] - %-18s (%4d) : %08x/%08x\n",
 127                rsnd_mod_name(mod), rsnd_mod_id(mod),
 128                rsnd_reg_name(gen, reg), reg, data, mask);
 129
 130}
 131
 132phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id)
 133{
 134        struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
 135
 136        return  gen->res[reg_id];
 137}
 138
 139#define rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf)         \
 140        _rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf, ARRAY_SIZE(conf))
 141static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
 142                                 int id_size,
 143                                 int reg_id,
 144                                 const char *name,
 145                                 const struct rsnd_regmap_field_conf *conf,
 146                                 int conf_size)
 147{
 148        struct platform_device *pdev = rsnd_priv_to_pdev(priv);
 149        struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
 150        struct device *dev = rsnd_priv_to_dev(priv);
 151        struct resource *res;
 152        struct regmap_config regc;
 153        struct regmap_field *regs;
 154        struct regmap *regmap;
 155        struct reg_field regf;
 156        void __iomem *base;
 157        int i;
 158
 159        memset(&regc, 0, sizeof(regc));
 160        regc.reg_bits = 32;
 161        regc.val_bits = 32;
 162        regc.reg_stride = 4;
 163        regc.name = name;
 164
 165        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
 166        if (!res)
 167                res = platform_get_resource(pdev, IORESOURCE_MEM, reg_id);
 168        if (!res)
 169                return -ENODEV;
 170
 171        base = devm_ioremap_resource(dev, res);
 172        if (IS_ERR(base))
 173                return PTR_ERR(base);
 174
 175        regmap = devm_regmap_init_mmio(dev, base, &regc);
 176        if (IS_ERR(regmap))
 177                return PTR_ERR(regmap);
 178
 179        /* RSND_BASE_MAX base */
 180        gen->base[reg_id] = base;
 181        gen->regmap[reg_id] = regmap;
 182        gen->res[reg_id] = res->start;
 183
 184        for (i = 0; i < conf_size; i++) {
 185
 186                regf.reg        = conf[i].reg_offset;
 187                regf.id_offset  = conf[i].id_offset;
 188                regf.lsb        = 0;
 189                regf.msb        = 31;
 190                regf.id_size    = id_size;
 191
 192                regs = devm_regmap_field_alloc(dev, regmap, regf);
 193                if (IS_ERR(regs))
 194                        return PTR_ERR(regs);
 195
 196                /* RSND_REG_MAX base */
 197                gen->regs[conf[i].idx] = regs;
 198                gen->reg_name[conf[i].idx] = conf[i].reg_name;
 199        }
 200
 201        return 0;
 202}
 203
 204/*
 205 *              Gen2
 206 */
 207static int rsnd_gen2_probe(struct rsnd_priv *priv)
 208{
 209        static const struct rsnd_regmap_field_conf conf_ssiu[] = {
 210                RSND_GEN_S_REG(SSI_MODE0,       0x800),
 211                RSND_GEN_S_REG(SSI_MODE1,       0x804),
 212                RSND_GEN_S_REG(SSI_MODE2,       0x808),
 213                RSND_GEN_S_REG(SSI_CONTROL,     0x810),
 214                RSND_GEN_S_REG(SSI_SYS_STATUS0, 0x840),
 215                RSND_GEN_S_REG(SSI_SYS_STATUS1, 0x844),
 216                RSND_GEN_S_REG(SSI_SYS_STATUS2, 0x848),
 217                RSND_GEN_S_REG(SSI_SYS_STATUS3, 0x84c),
 218                RSND_GEN_S_REG(SSI_SYS_STATUS4, 0x880),
 219                RSND_GEN_S_REG(SSI_SYS_STATUS5, 0x884),
 220                RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888),
 221                RSND_GEN_S_REG(SSI_SYS_STATUS7, 0x88c),
 222                RSND_GEN_S_REG(HDMI0_SEL,       0x9e0),
 223                RSND_GEN_S_REG(HDMI1_SEL,       0x9e4),
 224
 225                /* FIXME: it needs SSI_MODE2/3 in the future */
 226                RSND_GEN_M_REG(SSI_BUSIF_MODE,  0x0,    0x80),
 227                RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4,    0x80),
 228                RSND_GEN_M_REG(SSI_BUSIF_DALIGN,0x8,    0x80),
 229                RSND_GEN_M_REG(SSI_MODE,        0xc,    0x80),
 230                RSND_GEN_M_REG(SSI_CTRL,        0x10,   0x80),
 231                RSND_GEN_M_REG(SSI_INT_ENABLE,  0x18,   0x80),
 232        };
 233
 234        static const struct rsnd_regmap_field_conf conf_scu[] = {
 235                RSND_GEN_M_REG(SRC_I_BUSIF_MODE,0x0,    0x20),
 236                RSND_GEN_M_REG(SRC_O_BUSIF_MODE,0x4,    0x20),
 237                RSND_GEN_M_REG(SRC_BUSIF_DALIGN,0x8,    0x20),
 238                RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc,    0x20),
 239                RSND_GEN_M_REG(SRC_CTRL,        0x10,   0x20),
 240                RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18,   0x20),
 241                RSND_GEN_M_REG(CMD_BUSIF_MODE,  0x184,  0x20),
 242                RSND_GEN_M_REG(CMD_BUSIF_DALIGN,0x188,  0x20),
 243                RSND_GEN_M_REG(CMD_ROUTE_SLCT,  0x18c,  0x20),
 244                RSND_GEN_M_REG(CMD_CTRL,        0x190,  0x20),
 245                RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8),
 246                RSND_GEN_S_REG(SCU_SYS_INT_EN0, 0x1cc),
 247                RSND_GEN_S_REG(SCU_SYS_STATUS1, 0x1d0),
 248                RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1d4),
 249                RSND_GEN_M_REG(SRC_SWRSR,       0x200,  0x40),
 250                RSND_GEN_M_REG(SRC_SRCIR,       0x204,  0x40),
 251                RSND_GEN_M_REG(SRC_ADINR,       0x214,  0x40),
 252                RSND_GEN_M_REG(SRC_IFSCR,       0x21c,  0x40),
 253                RSND_GEN_M_REG(SRC_IFSVR,       0x220,  0x40),
 254                RSND_GEN_M_REG(SRC_SRCCR,       0x224,  0x40),
 255                RSND_GEN_M_REG(SRC_BSDSR,       0x22c,  0x40),
 256                RSND_GEN_M_REG(SRC_BSISR,       0x238,  0x40),
 257                RSND_GEN_M_REG(CTU_SWRSR,       0x500,  0x100),
 258                RSND_GEN_M_REG(CTU_CTUIR,       0x504,  0x100),
 259                RSND_GEN_M_REG(CTU_ADINR,       0x508,  0x100),
 260                RSND_GEN_M_REG(CTU_CPMDR,       0x510,  0x100),
 261                RSND_GEN_M_REG(CTU_SCMDR,       0x514,  0x100),
 262                RSND_GEN_M_REG(CTU_SV00R,       0x518,  0x100),
 263                RSND_GEN_M_REG(CTU_SV01R,       0x51c,  0x100),
 264                RSND_GEN_M_REG(CTU_SV02R,       0x520,  0x100),
 265                RSND_GEN_M_REG(CTU_SV03R,       0x524,  0x100),
 266                RSND_GEN_M_REG(CTU_SV04R,       0x528,  0x100),
 267                RSND_GEN_M_REG(CTU_SV05R,       0x52c,  0x100),
 268                RSND_GEN_M_REG(CTU_SV06R,       0x530,  0x100),
 269                RSND_GEN_M_REG(CTU_SV07R,       0x534,  0x100),
 270                RSND_GEN_M_REG(CTU_SV10R,       0x538,  0x100),
 271                RSND_GEN_M_REG(CTU_SV11R,       0x53c,  0x100),
 272                RSND_GEN_M_REG(CTU_SV12R,       0x540,  0x100),
 273                RSND_GEN_M_REG(CTU_SV13R,       0x544,  0x100),
 274                RSND_GEN_M_REG(CTU_SV14R,       0x548,  0x100),
 275                RSND_GEN_M_REG(CTU_SV15R,       0x54c,  0x100),
 276                RSND_GEN_M_REG(CTU_SV16R,       0x550,  0x100),
 277                RSND_GEN_M_REG(CTU_SV17R,       0x554,  0x100),
 278                RSND_GEN_M_REG(CTU_SV20R,       0x558,  0x100),
 279                RSND_GEN_M_REG(CTU_SV21R,       0x55c,  0x100),
 280                RSND_GEN_M_REG(CTU_SV22R,       0x560,  0x100),
 281                RSND_GEN_M_REG(CTU_SV23R,       0x564,  0x100),
 282                RSND_GEN_M_REG(CTU_SV24R,       0x568,  0x100),
 283                RSND_GEN_M_REG(CTU_SV25R,       0x56c,  0x100),
 284                RSND_GEN_M_REG(CTU_SV26R,       0x570,  0x100),
 285                RSND_GEN_M_REG(CTU_SV27R,       0x574,  0x100),
 286                RSND_GEN_M_REG(CTU_SV30R,       0x578,  0x100),
 287                RSND_GEN_M_REG(CTU_SV31R,       0x57c,  0x100),
 288                RSND_GEN_M_REG(CTU_SV32R,       0x580,  0x100),
 289                RSND_GEN_M_REG(CTU_SV33R,       0x584,  0x100),
 290                RSND_GEN_M_REG(CTU_SV34R,       0x588,  0x100),
 291                RSND_GEN_M_REG(CTU_SV35R,       0x58c,  0x100),
 292                RSND_GEN_M_REG(CTU_SV36R,       0x590,  0x100),
 293                RSND_GEN_M_REG(CTU_SV37R,       0x594,  0x100),
 294                RSND_GEN_M_REG(MIX_SWRSR,       0xd00,  0x40),
 295                RSND_GEN_M_REG(MIX_MIXIR,       0xd04,  0x40),
 296                RSND_GEN_M_REG(MIX_ADINR,       0xd08,  0x40),
 297                RSND_GEN_M_REG(MIX_MIXMR,       0xd10,  0x40),
 298                RSND_GEN_M_REG(MIX_MVPDR,       0xd14,  0x40),
 299                RSND_GEN_M_REG(MIX_MDBAR,       0xd18,  0x40),
 300                RSND_GEN_M_REG(MIX_MDBBR,       0xd1c,  0x40),
 301                RSND_GEN_M_REG(MIX_MDBCR,       0xd20,  0x40),
 302                RSND_GEN_M_REG(MIX_MDBDR,       0xd24,  0x40),
 303                RSND_GEN_M_REG(MIX_MDBER,       0xd28,  0x40),
 304                RSND_GEN_M_REG(DVC_SWRSR,       0xe00,  0x100),
 305                RSND_GEN_M_REG(DVC_DVUIR,       0xe04,  0x100),
 306                RSND_GEN_M_REG(DVC_ADINR,       0xe08,  0x100),
 307                RSND_GEN_M_REG(DVC_DVUCR,       0xe10,  0x100),
 308                RSND_GEN_M_REG(DVC_ZCMCR,       0xe14,  0x100),
 309                RSND_GEN_M_REG(DVC_VRCTR,       0xe18,  0x100),
 310                RSND_GEN_M_REG(DVC_VRPDR,       0xe1c,  0x100),
 311                RSND_GEN_M_REG(DVC_VRDBR,       0xe20,  0x100),
 312                RSND_GEN_M_REG(DVC_VOL0R,       0xe28,  0x100),
 313                RSND_GEN_M_REG(DVC_VOL1R,       0xe2c,  0x100),
 314                RSND_GEN_M_REG(DVC_VOL2R,       0xe30,  0x100),
 315                RSND_GEN_M_REG(DVC_VOL3R,       0xe34,  0x100),
 316                RSND_GEN_M_REG(DVC_VOL4R,       0xe38,  0x100),
 317                RSND_GEN_M_REG(DVC_VOL5R,       0xe3c,  0x100),
 318                RSND_GEN_M_REG(DVC_VOL6R,       0xe40,  0x100),
 319                RSND_GEN_M_REG(DVC_VOL7R,       0xe44,  0x100),
 320                RSND_GEN_M_REG(DVC_DVUER,       0xe48,  0x100),
 321        };
 322        static const struct rsnd_regmap_field_conf conf_adg[] = {
 323                RSND_GEN_S_REG(BRRA,            0x00),
 324                RSND_GEN_S_REG(BRRB,            0x04),
 325                RSND_GEN_S_REG(BRGCKR,          0x08),
 326                RSND_GEN_S_REG(AUDIO_CLK_SEL0,  0x0c),
 327                RSND_GEN_S_REG(AUDIO_CLK_SEL1,  0x10),
 328                RSND_GEN_S_REG(AUDIO_CLK_SEL2,  0x14),
 329                RSND_GEN_S_REG(DIV_EN,          0x30),
 330                RSND_GEN_S_REG(SRCIN_TIMSEL0,   0x34),
 331                RSND_GEN_S_REG(SRCIN_TIMSEL1,   0x38),
 332                RSND_GEN_S_REG(SRCIN_TIMSEL2,   0x3c),
 333                RSND_GEN_S_REG(SRCIN_TIMSEL3,   0x40),
 334                RSND_GEN_S_REG(SRCIN_TIMSEL4,   0x44),
 335                RSND_GEN_S_REG(SRCOUT_TIMSEL0,  0x48),
 336                RSND_GEN_S_REG(SRCOUT_TIMSEL1,  0x4c),
 337                RSND_GEN_S_REG(SRCOUT_TIMSEL2,  0x50),
 338                RSND_GEN_S_REG(SRCOUT_TIMSEL3,  0x54),
 339                RSND_GEN_S_REG(SRCOUT_TIMSEL4,  0x58),
 340                RSND_GEN_S_REG(CMDOUT_TIMSEL,   0x5c),
 341        };
 342        static const struct rsnd_regmap_field_conf conf_ssi[] = {
 343                RSND_GEN_M_REG(SSICR,           0x00,   0x40),
 344                RSND_GEN_M_REG(SSISR,           0x04,   0x40),
 345                RSND_GEN_M_REG(SSITDR,          0x08,   0x40),
 346                RSND_GEN_M_REG(SSIRDR,          0x0c,   0x40),
 347                RSND_GEN_M_REG(SSIWSR,          0x20,   0x40),
 348        };
 349        int ret_ssiu;
 350        int ret_scu;
 351        int ret_adg;
 352        int ret_ssi;
 353
 354        ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSIU, "ssiu", conf_ssiu);
 355        ret_scu  = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SCU,  "scu",  conf_scu);
 356        ret_adg  = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_ADG,  "adg",  conf_adg);
 357        ret_ssi  = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSI,  "ssi",  conf_ssi);
 358        if (ret_ssiu < 0 ||
 359            ret_scu  < 0 ||
 360            ret_adg  < 0 ||
 361            ret_ssi  < 0)
 362                return ret_ssiu | ret_scu | ret_adg | ret_ssi;
 363
 364        return 0;
 365}
 366
 367/*
 368 *              Gen1
 369 */
 370
 371static int rsnd_gen1_probe(struct rsnd_priv *priv)
 372{
 373        static const struct rsnd_regmap_field_conf conf_adg[] = {
 374                RSND_GEN_S_REG(BRRA,            0x00),
 375                RSND_GEN_S_REG(BRRB,            0x04),
 376                RSND_GEN_S_REG(BRGCKR,          0x08),
 377                RSND_GEN_S_REG(AUDIO_CLK_SEL0,  0x0c),
 378                RSND_GEN_S_REG(AUDIO_CLK_SEL1,  0x10),
 379        };
 380        static const struct rsnd_regmap_field_conf conf_ssi[] = {
 381                RSND_GEN_M_REG(SSICR,           0x00,   0x40),
 382                RSND_GEN_M_REG(SSISR,           0x04,   0x40),
 383                RSND_GEN_M_REG(SSITDR,          0x08,   0x40),
 384                RSND_GEN_M_REG(SSIRDR,          0x0c,   0x40),
 385                RSND_GEN_M_REG(SSIWSR,          0x20,   0x40),
 386        };
 387        int ret_adg;
 388        int ret_ssi;
 389
 390        ret_adg  = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, "adg", conf_adg);
 391        ret_ssi  = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI, "ssi", conf_ssi);
 392        if (ret_adg  < 0 ||
 393            ret_ssi  < 0)
 394                return ret_adg | ret_ssi;
 395
 396        return 0;
 397}
 398
 399/*
 400 *              Gen
 401 */
 402int rsnd_gen_probe(struct rsnd_priv *priv)
 403{
 404        struct device *dev = rsnd_priv_to_dev(priv);
 405        struct rsnd_gen *gen;
 406        int ret;
 407
 408        gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
 409        if (!gen)
 410                return -ENOMEM;
 411
 412        priv->gen = gen;
 413
 414        ret = -ENODEV;
 415        if (rsnd_is_gen1(priv))
 416                ret = rsnd_gen1_probe(priv);
 417        else if (rsnd_is_gen2(priv))
 418                ret = rsnd_gen2_probe(priv);
 419
 420        if (ret < 0)
 421                dev_err(dev, "unknown generation R-Car sound device\n");
 422
 423        return ret;
 424}
 425