13337744aSKuninori Morimoto /* 23337744aSKuninori Morimoto * Renesas R-Car Gen1 SRU/SSI support 33337744aSKuninori Morimoto * 43337744aSKuninori Morimoto * Copyright (C) 2013 Renesas Solutions Corp. 53337744aSKuninori Morimoto * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 63337744aSKuninori Morimoto * 73337744aSKuninori Morimoto * This program is free software; you can redistribute it and/or modify 83337744aSKuninori Morimoto * it under the terms of the GNU General Public License version 2 as 93337744aSKuninori Morimoto * published by the Free Software Foundation. 103337744aSKuninori Morimoto */ 113337744aSKuninori Morimoto #include "rsnd.h" 123337744aSKuninori Morimoto 133337744aSKuninori Morimoto struct rsnd_gen_ops { 14072188b6SKuninori Morimoto int (*probe)(struct platform_device *pdev, 15072188b6SKuninori Morimoto struct rcar_snd_info *info, 16072188b6SKuninori Morimoto struct rsnd_priv *priv); 17072188b6SKuninori Morimoto void (*remove)(struct platform_device *pdev, 18072188b6SKuninori Morimoto struct rsnd_priv *priv); 193337744aSKuninori Morimoto }; 203337744aSKuninori Morimoto 213337744aSKuninori Morimoto struct rsnd_gen { 223337744aSKuninori Morimoto void __iomem *base[RSND_BASE_MAX]; 233337744aSKuninori Morimoto 243337744aSKuninori Morimoto struct rsnd_gen_ops *ops; 2555e5b6fdSKuninori Morimoto 2655e5b6fdSKuninori Morimoto struct regmap *regmap; 2755e5b6fdSKuninori Morimoto struct regmap_field *regs[RSND_REG_MAX]; 283337744aSKuninori Morimoto }; 293337744aSKuninori Morimoto 303337744aSKuninori Morimoto #define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) 313337744aSKuninori Morimoto 3255e5b6fdSKuninori Morimoto #define RSND_REG_SET(gen, id, reg_id, offset, _id_offset, _id_size) \ 3355e5b6fdSKuninori Morimoto [id] = { \ 3455e5b6fdSKuninori Morimoto .reg = (unsigned int)gen->base[reg_id] + offset, \ 3555e5b6fdSKuninori Morimoto .lsb = 0, \ 3655e5b6fdSKuninori Morimoto .msb = 31, \ 3755e5b6fdSKuninori Morimoto .id_size = _id_size, \ 3855e5b6fdSKuninori Morimoto .id_offset = _id_offset, \ 3955e5b6fdSKuninori Morimoto } 4055e5b6fdSKuninori Morimoto 4155e5b6fdSKuninori Morimoto /* 4255e5b6fdSKuninori Morimoto * basic function 4355e5b6fdSKuninori Morimoto */ 4455e5b6fdSKuninori Morimoto static int rsnd_regmap_write32(void *context, const void *_data, size_t count) 4555e5b6fdSKuninori Morimoto { 4655e5b6fdSKuninori Morimoto struct rsnd_priv *priv = context; 4755e5b6fdSKuninori Morimoto struct device *dev = rsnd_priv_to_dev(priv); 4855e5b6fdSKuninori Morimoto u32 *data = (u32 *)_data; 4955e5b6fdSKuninori Morimoto u32 val = data[1]; 5055e5b6fdSKuninori Morimoto void __iomem *reg = (void *)data[0]; 5155e5b6fdSKuninori Morimoto 5255e5b6fdSKuninori Morimoto iowrite32(val, reg); 5355e5b6fdSKuninori Morimoto 5455e5b6fdSKuninori Morimoto dev_dbg(dev, "w %p : %08x\n", reg, val); 5555e5b6fdSKuninori Morimoto 5655e5b6fdSKuninori Morimoto return 0; 5755e5b6fdSKuninori Morimoto } 5855e5b6fdSKuninori Morimoto 5955e5b6fdSKuninori Morimoto static int rsnd_regmap_read32(void *context, 6055e5b6fdSKuninori Morimoto const void *_data, size_t reg_size, 6155e5b6fdSKuninori Morimoto void *_val, size_t val_size) 6255e5b6fdSKuninori Morimoto { 6355e5b6fdSKuninori Morimoto struct rsnd_priv *priv = context; 6455e5b6fdSKuninori Morimoto struct device *dev = rsnd_priv_to_dev(priv); 6555e5b6fdSKuninori Morimoto u32 *data = (u32 *)_data; 6655e5b6fdSKuninori Morimoto u32 *val = (u32 *)_val; 6755e5b6fdSKuninori Morimoto void __iomem *reg = (void *)data[0]; 6855e5b6fdSKuninori Morimoto 6955e5b6fdSKuninori Morimoto *val = ioread32(reg); 7055e5b6fdSKuninori Morimoto 7155e5b6fdSKuninori Morimoto dev_dbg(dev, "r %p : %08x\n", reg, *val); 7255e5b6fdSKuninori Morimoto 7355e5b6fdSKuninori Morimoto return 0; 7455e5b6fdSKuninori Morimoto } 7555e5b6fdSKuninori Morimoto 7655e5b6fdSKuninori Morimoto static struct regmap_bus rsnd_regmap_bus = { 7755e5b6fdSKuninori Morimoto .write = rsnd_regmap_write32, 7855e5b6fdSKuninori Morimoto .read = rsnd_regmap_read32, 7955e5b6fdSKuninori Morimoto .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, 8055e5b6fdSKuninori Morimoto .val_format_endian_default = REGMAP_ENDIAN_NATIVE, 8155e5b6fdSKuninori Morimoto }; 8255e5b6fdSKuninori Morimoto 8342ee5d22SKuninori Morimoto static int rsnd_is_accessible_reg(struct rsnd_priv *priv, 8442ee5d22SKuninori Morimoto struct rsnd_gen *gen, enum rsnd_reg reg) 8542ee5d22SKuninori Morimoto { 8642ee5d22SKuninori Morimoto if (!gen->regs[reg]) { 8742ee5d22SKuninori Morimoto struct device *dev = rsnd_priv_to_dev(priv); 8842ee5d22SKuninori Morimoto 8942ee5d22SKuninori Morimoto dev_err(dev, "unsupported register access %x\n", reg); 9042ee5d22SKuninori Morimoto return 0; 9142ee5d22SKuninori Morimoto } 9242ee5d22SKuninori Morimoto 9342ee5d22SKuninori Morimoto return 1; 9442ee5d22SKuninori Morimoto } 9542ee5d22SKuninori Morimoto 9655e5b6fdSKuninori Morimoto u32 rsnd_read(struct rsnd_priv *priv, 9755e5b6fdSKuninori Morimoto struct rsnd_mod *mod, enum rsnd_reg reg) 9855e5b6fdSKuninori Morimoto { 9955e5b6fdSKuninori Morimoto struct rsnd_gen *gen = rsnd_priv_to_gen(priv); 10055e5b6fdSKuninori Morimoto u32 val; 10155e5b6fdSKuninori Morimoto 10242ee5d22SKuninori Morimoto if (!rsnd_is_accessible_reg(priv, gen, reg)) 10342ee5d22SKuninori Morimoto return 0; 10442ee5d22SKuninori Morimoto 10555e5b6fdSKuninori Morimoto regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val); 10655e5b6fdSKuninori Morimoto 10755e5b6fdSKuninori Morimoto return val; 10855e5b6fdSKuninori Morimoto } 10955e5b6fdSKuninori Morimoto 11055e5b6fdSKuninori Morimoto void rsnd_write(struct rsnd_priv *priv, 11155e5b6fdSKuninori Morimoto struct rsnd_mod *mod, 11255e5b6fdSKuninori Morimoto enum rsnd_reg reg, u32 data) 11355e5b6fdSKuninori Morimoto { 11455e5b6fdSKuninori Morimoto struct rsnd_gen *gen = rsnd_priv_to_gen(priv); 11555e5b6fdSKuninori Morimoto 11642ee5d22SKuninori Morimoto if (!rsnd_is_accessible_reg(priv, gen, reg)) 11742ee5d22SKuninori Morimoto return; 11842ee5d22SKuninori Morimoto 11955e5b6fdSKuninori Morimoto regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); 12055e5b6fdSKuninori Morimoto } 12155e5b6fdSKuninori Morimoto 12255e5b6fdSKuninori Morimoto void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, 12355e5b6fdSKuninori Morimoto enum rsnd_reg reg, u32 mask, u32 data) 12455e5b6fdSKuninori Morimoto { 12555e5b6fdSKuninori Morimoto struct rsnd_gen *gen = rsnd_priv_to_gen(priv); 12655e5b6fdSKuninori Morimoto 12742ee5d22SKuninori Morimoto if (!rsnd_is_accessible_reg(priv, gen, reg)) 12842ee5d22SKuninori Morimoto return; 12942ee5d22SKuninori Morimoto 13055e5b6fdSKuninori Morimoto regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), 13155e5b6fdSKuninori Morimoto mask, data); 13255e5b6fdSKuninori Morimoto } 13355e5b6fdSKuninori Morimoto 134c1e6cc5eSKuninori Morimoto static int rsnd_gen_regmap_init(struct rsnd_priv *priv, 135c1e6cc5eSKuninori Morimoto struct rsnd_gen *gen, 136c1e6cc5eSKuninori Morimoto struct reg_field *regf) 137c1e6cc5eSKuninori Morimoto { 138c1e6cc5eSKuninori Morimoto int i; 139c1e6cc5eSKuninori Morimoto struct device *dev = rsnd_priv_to_dev(priv); 140c1e6cc5eSKuninori Morimoto struct regmap_config regc; 141c1e6cc5eSKuninori Morimoto 142c1e6cc5eSKuninori Morimoto memset(®c, 0, sizeof(regc)); 143c1e6cc5eSKuninori Morimoto regc.reg_bits = 32; 144c1e6cc5eSKuninori Morimoto regc.val_bits = 32; 145c1e6cc5eSKuninori Morimoto 146c1e6cc5eSKuninori Morimoto gen->regmap = devm_regmap_init(dev, &rsnd_regmap_bus, priv, ®c); 147c1e6cc5eSKuninori Morimoto if (IS_ERR(gen->regmap)) { 148c1e6cc5eSKuninori Morimoto dev_err(dev, "regmap error %ld\n", PTR_ERR(gen->regmap)); 149c1e6cc5eSKuninori Morimoto return PTR_ERR(gen->regmap); 150c1e6cc5eSKuninori Morimoto } 151c1e6cc5eSKuninori Morimoto 152c1e6cc5eSKuninori Morimoto for (i = 0; i < RSND_REG_MAX; i++) { 15342ee5d22SKuninori Morimoto gen->regs[i] = NULL; 15442ee5d22SKuninori Morimoto if (!regf[i].reg) 15542ee5d22SKuninori Morimoto continue; 15642ee5d22SKuninori Morimoto 157c1e6cc5eSKuninori Morimoto gen->regs[i] = devm_regmap_field_alloc(dev, gen->regmap, regf[i]); 158c1e6cc5eSKuninori Morimoto if (IS_ERR(gen->regs[i])) 159c1e6cc5eSKuninori Morimoto return PTR_ERR(gen->regs[i]); 160c1e6cc5eSKuninori Morimoto 161c1e6cc5eSKuninori Morimoto } 162c1e6cc5eSKuninori Morimoto 163c1e6cc5eSKuninori Morimoto return 0; 164c1e6cc5eSKuninori Morimoto } 1653337744aSKuninori Morimoto 166994a9df1SKuninori Morimoto int rsnd_gen_path_init(struct rsnd_priv *priv, 16707539c1dSKuninori Morimoto struct rsnd_dai *rdai, 16807539c1dSKuninori Morimoto struct rsnd_dai_stream *io) 16907539c1dSKuninori Morimoto { 17007539c1dSKuninori Morimoto struct rsnd_mod *mod; 17107539c1dSKuninori Morimoto int ret; 17207539c1dSKuninori Morimoto int id; 17307539c1dSKuninori Morimoto 17407539c1dSKuninori Morimoto /* 17507539c1dSKuninori Morimoto * Gen1 is created by SRU/SSI, and this SRU is base module of 17607539c1dSKuninori Morimoto * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU) 17707539c1dSKuninori Morimoto * 17807539c1dSKuninori Morimoto * Easy image is.. 17907539c1dSKuninori Morimoto * Gen1 SRU = Gen2 SCU + SSIU + etc 18007539c1dSKuninori Morimoto * 18107539c1dSKuninori Morimoto * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is 18207539c1dSKuninori Morimoto * using fixed path. 18307539c1dSKuninori Morimoto * 18407539c1dSKuninori Morimoto * Then, SSI id = SCU id here 18507539c1dSKuninori Morimoto */ 18607539c1dSKuninori Morimoto 1874b4dab82SKuninori Morimoto /* get SSI's ID */ 1884b4dab82SKuninori Morimoto mod = rsnd_ssi_mod_get_frm_dai(priv, 1894b4dab82SKuninori Morimoto rsnd_dai_id(priv, rdai), 1904b4dab82SKuninori Morimoto rsnd_dai_is_play(rdai, io)); 1914b4dab82SKuninori Morimoto id = rsnd_mod_id(mod); 19207539c1dSKuninori Morimoto 193ae5c3223SKuninori Morimoto /* SSI */ 194ae5c3223SKuninori Morimoto mod = rsnd_ssi_mod_get(priv, id); 195ae5c3223SKuninori Morimoto ret = rsnd_dai_connect(rdai, mod, io); 196ae5c3223SKuninori Morimoto if (ret < 0) 197ae5c3223SKuninori Morimoto return ret; 198ae5c3223SKuninori Morimoto 19907539c1dSKuninori Morimoto /* SCU */ 20007539c1dSKuninori Morimoto mod = rsnd_scu_mod_get(priv, id); 20107539c1dSKuninori Morimoto ret = rsnd_dai_connect(rdai, mod, io); 20207539c1dSKuninori Morimoto 20307539c1dSKuninori Morimoto return ret; 20407539c1dSKuninori Morimoto } 20507539c1dSKuninori Morimoto 206994a9df1SKuninori Morimoto int rsnd_gen_path_exit(struct rsnd_priv *priv, 20707539c1dSKuninori Morimoto struct rsnd_dai *rdai, 20807539c1dSKuninori Morimoto struct rsnd_dai_stream *io) 20907539c1dSKuninori Morimoto { 21007539c1dSKuninori Morimoto struct rsnd_mod *mod, *n; 21107539c1dSKuninori Morimoto int ret = 0; 21207539c1dSKuninori Morimoto 21307539c1dSKuninori Morimoto /* 21407539c1dSKuninori Morimoto * remove all mod from rdai 21507539c1dSKuninori Morimoto */ 21607539c1dSKuninori Morimoto for_each_rsnd_mod(mod, n, io) 21707539c1dSKuninori Morimoto ret |= rsnd_dai_disconnect(mod); 21807539c1dSKuninori Morimoto 21907539c1dSKuninori Morimoto return ret; 22007539c1dSKuninori Morimoto } 22107539c1dSKuninori Morimoto 222994a9df1SKuninori Morimoto /* 223994a9df1SKuninori Morimoto * Gen2 224994a9df1SKuninori Morimoto * will be filled in the future 225994a9df1SKuninori Morimoto */ 226994a9df1SKuninori Morimoto 227994a9df1SKuninori Morimoto /* 228994a9df1SKuninori Morimoto * Gen1 229994a9df1SKuninori Morimoto */ 230994a9df1SKuninori Morimoto 23155e5b6fdSKuninori Morimoto /* single address mapping */ 23255e5b6fdSKuninori Morimoto #define RSND_GEN1_S_REG(gen, reg, id, offset) \ 23355e5b6fdSKuninori Morimoto RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN1_##reg, offset, 0, 9) 23407539c1dSKuninori Morimoto 23555e5b6fdSKuninori Morimoto /* multi address mapping */ 23655e5b6fdSKuninori Morimoto #define RSND_GEN1_M_REG(gen, reg, id, offset, _id_offset) \ 23755e5b6fdSKuninori Morimoto RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN1_##reg, offset, _id_offset, 9) 23855e5b6fdSKuninori Morimoto 23955e5b6fdSKuninori Morimoto static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) 24007539c1dSKuninori Morimoto { 24155e5b6fdSKuninori Morimoto struct reg_field regf[RSND_REG_MAX] = { 24255e5b6fdSKuninori Morimoto RSND_GEN1_S_REG(gen, SRU, SRC_ROUTE_SEL, 0x00), 24355e5b6fdSKuninori Morimoto RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL0, 0x08), 24455e5b6fdSKuninori Morimoto RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL1, 0x0c), 24555e5b6fdSKuninori Morimoto RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL2, 0x10), 24655e5b6fdSKuninori Morimoto RSND_GEN1_S_REG(gen, SRU, SRC_CTRL, 0xc0), 24755e5b6fdSKuninori Morimoto RSND_GEN1_S_REG(gen, SRU, SSI_MODE0, 0xD0), 24855e5b6fdSKuninori Morimoto RSND_GEN1_S_REG(gen, SRU, SSI_MODE1, 0xD4), 24955e5b6fdSKuninori Morimoto RSND_GEN1_M_REG(gen, SRU, BUSIF_MODE, 0x20, 0x4), 25055e5b6fdSKuninori Morimoto RSND_GEN1_M_REG(gen, SRU, BUSIF_ADINR, 0x214, 0x40), 251dfc9403bSKuninori Morimoto 25255e5b6fdSKuninori Morimoto RSND_GEN1_S_REG(gen, ADG, BRRA, 0x00), 25355e5b6fdSKuninori Morimoto RSND_GEN1_S_REG(gen, ADG, BRRB, 0x04), 25455e5b6fdSKuninori Morimoto RSND_GEN1_S_REG(gen, ADG, SSICKR, 0x08), 25555e5b6fdSKuninori Morimoto RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL0, 0x0c), 25655e5b6fdSKuninori Morimoto RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL1, 0x10), 257ae5c3223SKuninori Morimoto 25855e5b6fdSKuninori Morimoto RSND_GEN1_M_REG(gen, SSI, SSICR, 0x00, 0x40), 25955e5b6fdSKuninori Morimoto RSND_GEN1_M_REG(gen, SSI, SSISR, 0x04, 0x40), 26055e5b6fdSKuninori Morimoto RSND_GEN1_M_REG(gen, SSI, SSITDR, 0x08, 0x40), 26155e5b6fdSKuninori Morimoto RSND_GEN1_M_REG(gen, SSI, SSIRDR, 0x0c, 0x40), 26255e5b6fdSKuninori Morimoto RSND_GEN1_M_REG(gen, SSI, SSIWSR, 0x20, 0x40), 26355e5b6fdSKuninori Morimoto }; 26455e5b6fdSKuninori Morimoto 265c1e6cc5eSKuninori Morimoto return rsnd_gen_regmap_init(priv, gen, regf); 26607539c1dSKuninori Morimoto } 26707539c1dSKuninori Morimoto 2683337744aSKuninori Morimoto static int rsnd_gen1_probe(struct platform_device *pdev, 2693337744aSKuninori Morimoto struct rcar_snd_info *info, 2703337744aSKuninori Morimoto struct rsnd_priv *priv) 2713337744aSKuninori Morimoto { 27207539c1dSKuninori Morimoto struct device *dev = rsnd_priv_to_dev(priv); 27307539c1dSKuninori Morimoto struct rsnd_gen *gen = rsnd_priv_to_gen(priv); 27407539c1dSKuninori Morimoto struct resource *sru_res; 275dfc9403bSKuninori Morimoto struct resource *adg_res; 276ae5c3223SKuninori Morimoto struct resource *ssi_res; 27755e5b6fdSKuninori Morimoto int ret; 27807539c1dSKuninori Morimoto 27907539c1dSKuninori Morimoto /* 28007539c1dSKuninori Morimoto * map address 28107539c1dSKuninori Morimoto */ 28207539c1dSKuninori Morimoto sru_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SRU); 283dfc9403bSKuninori Morimoto adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_ADG); 284ae5c3223SKuninori Morimoto ssi_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SSI); 28507539c1dSKuninori Morimoto 28607539c1dSKuninori Morimoto gen->base[RSND_GEN1_SRU] = devm_ioremap_resource(dev, sru_res); 287dfc9403bSKuninori Morimoto gen->base[RSND_GEN1_ADG] = devm_ioremap_resource(dev, adg_res); 288ae5c3223SKuninori Morimoto gen->base[RSND_GEN1_SSI] = devm_ioremap_resource(dev, ssi_res); 28970263cb4SWei Yongjun if (IS_ERR(gen->base[RSND_GEN1_SRU]) || 29070263cb4SWei Yongjun IS_ERR(gen->base[RSND_GEN1_ADG]) || 29170263cb4SWei Yongjun IS_ERR(gen->base[RSND_GEN1_SSI])) 29207539c1dSKuninori Morimoto return -ENODEV; 29307539c1dSKuninori Morimoto 29455e5b6fdSKuninori Morimoto ret = rsnd_gen1_regmap_init(priv, gen); 29555e5b6fdSKuninori Morimoto if (ret < 0) 29655e5b6fdSKuninori Morimoto return ret; 29707539c1dSKuninori Morimoto 29807539c1dSKuninori Morimoto dev_dbg(dev, "Gen1 device probed\n"); 29907539c1dSKuninori Morimoto dev_dbg(dev, "SRU : %08x => %p\n", sru_res->start, 30007539c1dSKuninori Morimoto gen->base[RSND_GEN1_SRU]); 301dfc9403bSKuninori Morimoto dev_dbg(dev, "ADG : %08x => %p\n", adg_res->start, 302dfc9403bSKuninori Morimoto gen->base[RSND_GEN1_ADG]); 303ae5c3223SKuninori Morimoto dev_dbg(dev, "SSI : %08x => %p\n", ssi_res->start, 304ae5c3223SKuninori Morimoto gen->base[RSND_GEN1_SSI]); 30507539c1dSKuninori Morimoto 3063337744aSKuninori Morimoto return 0; 307ae5c3223SKuninori Morimoto 3083337744aSKuninori Morimoto } 3093337744aSKuninori Morimoto 3103337744aSKuninori Morimoto static void rsnd_gen1_remove(struct platform_device *pdev, 3113337744aSKuninori Morimoto struct rsnd_priv *priv) 3123337744aSKuninori Morimoto { 3133337744aSKuninori Morimoto } 3143337744aSKuninori Morimoto 315072188b6SKuninori Morimoto static struct rsnd_gen_ops rsnd_gen1_ops = { 316072188b6SKuninori Morimoto .probe = rsnd_gen1_probe, 317072188b6SKuninori Morimoto .remove = rsnd_gen1_remove, 318072188b6SKuninori Morimoto }; 319072188b6SKuninori Morimoto 3203337744aSKuninori Morimoto /* 3213337744aSKuninori Morimoto * Gen 3223337744aSKuninori Morimoto */ 3233337744aSKuninori Morimoto int rsnd_gen_probe(struct platform_device *pdev, 3243337744aSKuninori Morimoto struct rcar_snd_info *info, 3253337744aSKuninori Morimoto struct rsnd_priv *priv) 3263337744aSKuninori Morimoto { 3273337744aSKuninori Morimoto struct device *dev = rsnd_priv_to_dev(priv); 3283337744aSKuninori Morimoto struct rsnd_gen *gen; 3293337744aSKuninori Morimoto 3303337744aSKuninori Morimoto gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL); 3313337744aSKuninori Morimoto if (!gen) { 3323337744aSKuninori Morimoto dev_err(dev, "GEN allocate failed\n"); 3333337744aSKuninori Morimoto return -ENOMEM; 3343337744aSKuninori Morimoto } 3353337744aSKuninori Morimoto 336072188b6SKuninori Morimoto if (rsnd_is_gen1(priv)) 337072188b6SKuninori Morimoto gen->ops = &rsnd_gen1_ops; 338072188b6SKuninori Morimoto 339072188b6SKuninori Morimoto if (!gen->ops) { 340072188b6SKuninori Morimoto dev_err(dev, "unknown generation R-Car sound device\n"); 341072188b6SKuninori Morimoto return -ENODEV; 342072188b6SKuninori Morimoto } 343072188b6SKuninori Morimoto 3443337744aSKuninori Morimoto priv->gen = gen; 3453337744aSKuninori Morimoto 346072188b6SKuninori Morimoto return gen->ops->probe(pdev, info, priv); 3473337744aSKuninori Morimoto } 3483337744aSKuninori Morimoto 3493337744aSKuninori Morimoto void rsnd_gen_remove(struct platform_device *pdev, 3503337744aSKuninori Morimoto struct rsnd_priv *priv) 3513337744aSKuninori Morimoto { 352072188b6SKuninori Morimoto struct rsnd_gen *gen = rsnd_priv_to_gen(priv); 353072188b6SKuninori Morimoto 354072188b6SKuninori Morimoto gen->ops->remove(pdev, priv); 3553337744aSKuninori Morimoto } 356