brintos

brintos / linux-shallow public Read only

0
0
Text · 19.2 KiB · 7e771a1 Raw
801 lines · c
1// SPDX-License-Identifier: GPL-2.0+2//3// siu_dai.c - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral.4//5// Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>6// Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>7 8#include <linux/delay.h>9#include <linux/firmware.h>10#include <linux/pm_runtime.h>11#include <linux/slab.h>12#include <linux/module.h>13 14#include <asm/clock.h>15#include <asm/siu.h>16 17#include <sound/control.h>18#include <sound/soc.h>19 20#include "siu.h"21 22/* Board specifics */23#if defined(CONFIG_CPU_SUBTYPE_SH7722)24# define SIU_MAX_VOLUME		0x100025#else26# define SIU_MAX_VOLUME		0x7fff27#endif28 29#define PRAM_SIZE	0x200030#define XRAM_SIZE	0x80031#define YRAM_SIZE	0x80032 33#define XRAM_OFFSET	0x400034#define YRAM_OFFSET	0x600035#define REG_OFFSET	0xc00036 37#define PLAYBACK_ENABLED	138#define CAPTURE_ENABLED		239 40#define VOLUME_CAPTURE		041#define VOLUME_PLAYBACK		142#define DFLT_VOLUME_LEVEL	0x0800080043 44/*45 * SPDIF is only available on port A and on some SIU implementations it is only46 * available for input. Due to the lack of hardware to test it, SPDIF is left47 * disabled in this driver version48 */49struct format_flag {50	u32	i2s;51	u32	pcm;52	u32	spdif;53	u32	mask;54};55 56struct port_flag {57	struct format_flag	playback;58	struct format_flag	capture;59};60 61struct siu_info *siu_i2s_data;62 63static struct port_flag siu_flags[SIU_PORT_NUM] = {64	[SIU_PORT_A] = {65		.playback = {66			.i2s	= 0x50000000,67			.pcm	= 0x40000000,68			.spdif	= 0x80000000,	/* not on all SIU versions */69			.mask	= 0xd0000000,70		},71		.capture = {72			.i2s	= 0x05000000,73			.pcm	= 0x04000000,74			.spdif	= 0x08000000,75			.mask	= 0x0d000000,76		},77	},78	[SIU_PORT_B] = {79		.playback = {80			.i2s	= 0x00500000,81			.pcm	= 0x00400000,82			.spdif	= 0,		/* impossible - turn off */83			.mask	= 0x00500000,84		},85		.capture = {86			.i2s	= 0x00050000,87			.pcm	= 0x00040000,88			.spdif	= 0,		/* impossible - turn off */89			.mask	= 0x00050000,90		},91	},92};93 94static void siu_dai_start(struct siu_port *port_info)95{96	struct siu_info *info = siu_i2s_data;97	u32 __iomem *base = info->reg;98 99	dev_dbg(port_info->pcm->card->dev, "%s\n", __func__);100 101	/* Issue software reset to siu */102	siu_write32(base + SIU_SRCTL, 0);103 104	/* Wait for the reset to take effect */105	udelay(1);106 107	port_info->stfifo = 0;108	port_info->trdat = 0;109 110	/* portA, portB, SIU operate */111	siu_write32(base + SIU_SRCTL, 0x301);112 113	/* portA=256fs, portB=256fs */114	siu_write32(base + SIU_CKCTL, 0x40400000);115 116	/* portA's BRG does not divide SIUCKA */117	siu_write32(base + SIU_BRGASEL, 0);118	siu_write32(base + SIU_BRRA, 0);119 120	/* portB's BRG divides SIUCKB by half */121	siu_write32(base + SIU_BRGBSEL, 1);122	siu_write32(base + SIU_BRRB, 0);123 124	siu_write32(base + SIU_IFCTL, 0x44440000);125 126	/* portA: 32 bit/fs, master; portB: 32 bit/fs, master */127	siu_write32(base + SIU_SFORM, 0x0c0c0000);128 129	/*130	 * Volume levels: looks like the DSP firmware implements volume controls131	 * differently from what's described in the datasheet132	 */133	siu_write32(base + SIU_SBDVCA, port_info->playback.volume);134	siu_write32(base + SIU_SBDVCB, port_info->capture.volume);135}136 137static void siu_dai_stop(struct siu_port *port_info)138{139	struct siu_info *info = siu_i2s_data;140	u32 __iomem *base = info->reg;141 142	/* SIU software reset */143	siu_write32(base + SIU_SRCTL, 0);144}145 146static void siu_dai_spbAselect(struct siu_port *port_info)147{148	struct siu_info *info = siu_i2s_data;149	struct siu_firmware *fw = &info->fw;150	u32 *ydef = fw->yram0;151	u32 idx;152 153	/* path A use */154	if (!info->port_id)155		idx = 1;		/* portA */156	else157		idx = 2;		/* portB */158 159	ydef[0] = (fw->spbpar[idx].ab1a << 16) |160		(fw->spbpar[idx].ab0a << 8) |161		(fw->spbpar[idx].dir << 7) | 3;162	ydef[1] = fw->yram0[1];	/* 0x03000300 */163	ydef[2] = (16 / 2) << 24;164	ydef[3] = fw->yram0[3];	/* 0 */165	ydef[4] = fw->yram0[4];	/* 0 */166	ydef[7] = fw->spbpar[idx].event;167	port_info->stfifo |= fw->spbpar[idx].stfifo;168	port_info->trdat |= fw->spbpar[idx].trdat;169}170 171static void siu_dai_spbBselect(struct siu_port *port_info)172{173	struct siu_info *info = siu_i2s_data;174	struct siu_firmware *fw = &info->fw;175	u32 *ydef = fw->yram0;176	u32 idx;177 178	/* path B use */179	if (!info->port_id)180		idx = 7;		/* portA */181	else182		idx = 8;		/* portB */183 184	ydef[5] = (fw->spbpar[idx].ab1a << 16) |185		(fw->spbpar[idx].ab0a << 8) | 1;186	ydef[6] = fw->spbpar[idx].event;187	port_info->stfifo |= fw->spbpar[idx].stfifo;188	port_info->trdat |= fw->spbpar[idx].trdat;189}190 191static void siu_dai_open(struct siu_stream *siu_stream)192{193	struct siu_info *info = siu_i2s_data;194	u32 __iomem *base = info->reg;195	u32 srctl, ifctl;196 197	srctl = siu_read32(base + SIU_SRCTL);198	ifctl = siu_read32(base + SIU_IFCTL);199 200	switch (info->port_id) {201	case SIU_PORT_A:202		/* portA operates */203		srctl |= 0x200;204		ifctl &= ~0xc2;205		break;206	case SIU_PORT_B:207		/* portB operates */208		srctl |= 0x100;209		ifctl &= ~0x31;210		break;211	}212 213	siu_write32(base + SIU_SRCTL, srctl);214	/* Unmute and configure portA */215	siu_write32(base + SIU_IFCTL, ifctl);216}217 218/*219 * At the moment only fixed Left-upper, Left-lower, Right-upper, Right-lower220 * packing is supported221 */222static void siu_dai_pcmdatapack(struct siu_stream *siu_stream)223{224	struct siu_info *info = siu_i2s_data;225	u32 __iomem *base = info->reg;226	u32 dpak;227 228	dpak = siu_read32(base + SIU_DPAK);229 230	switch (info->port_id) {231	case SIU_PORT_A:232		dpak &= ~0xc0000000;233		break;234	case SIU_PORT_B:235		dpak &= ~0x00c00000;236		break;237	}238 239	siu_write32(base + SIU_DPAK, dpak);240}241 242static int siu_dai_spbstart(struct siu_port *port_info)243{244	struct siu_info *info = siu_i2s_data;245	u32 __iomem *base = info->reg;246	struct siu_firmware *fw = &info->fw;247	u32 *ydef = fw->yram0;248	int cnt;249	u32 __iomem *add;250	u32 *ptr;251 252	/* Load SPB Program in PRAM */253	ptr = fw->pram0;254	add = info->pram;255	for (cnt = 0; cnt < PRAM0_SIZE; cnt++, add++, ptr++)256		siu_write32(add, *ptr);257 258	ptr = fw->pram1;259	add = info->pram + (0x0100 / sizeof(u32));260	for (cnt = 0; cnt < PRAM1_SIZE; cnt++, add++, ptr++)261		siu_write32(add, *ptr);262 263	/* XRAM initialization */264	add = info->xram;265	for (cnt = 0; cnt < XRAM0_SIZE + XRAM1_SIZE + XRAM2_SIZE; cnt++, add++)266		siu_write32(add, 0);267 268	/* YRAM variable area initialization */269	add = info->yram;270	for (cnt = 0; cnt < YRAM_DEF_SIZE; cnt++, add++)271		siu_write32(add, ydef[cnt]);272 273	/* YRAM FIR coefficient area initialization */274	add = info->yram + (0x0200 / sizeof(u32));275	for (cnt = 0; cnt < YRAM_FIR_SIZE; cnt++, add++)276		siu_write32(add, fw->yram_fir_coeff[cnt]);277 278	/* YRAM IIR coefficient area initialization */279	add = info->yram + (0x0600 / sizeof(u32));280	for (cnt = 0; cnt < YRAM_IIR_SIZE; cnt++, add++)281		siu_write32(add, 0);282 283	siu_write32(base + SIU_TRDAT, port_info->trdat);284	port_info->trdat = 0x0;285 286 287	/* SPB start condition: software */288	siu_write32(base + SIU_SBACTIV, 0);289	/* Start SPB */290	siu_write32(base + SIU_SBCTL, 0xc0000000);291	/* Wait for program to halt */292	cnt = 0x10000;293	while (--cnt && siu_read32(base + SIU_SBCTL) != 0x80000000)294		cpu_relax();295 296	if (!cnt)297		return -EBUSY;298 299	/* SPB program start address setting */300	siu_write32(base + SIU_SBPSET, 0x00400000);301	/* SPB hardware start(FIFOCTL source) */302	siu_write32(base + SIU_SBACTIV, 0xc0000000);303 304	return 0;305}306 307static void siu_dai_spbstop(struct siu_port *port_info)308{309	struct siu_info *info = siu_i2s_data;310	u32 __iomem *base = info->reg;311 312	siu_write32(base + SIU_SBACTIV, 0);313	/* SPB stop */314	siu_write32(base + SIU_SBCTL, 0);315 316	port_info->stfifo = 0;317}318 319/*		API functions		*/320 321/* Playback and capture hardware properties are identical */322static const struct snd_pcm_hardware siu_dai_pcm_hw = {323	.info			= SNDRV_PCM_INFO_INTERLEAVED,324	.formats		= SNDRV_PCM_FMTBIT_S16,325	.rates			= SNDRV_PCM_RATE_8000_48000,326	.rate_min		= 8000,327	.rate_max		= 48000,328	.channels_min		= 2,329	.channels_max		= 2,330	.buffer_bytes_max	= SIU_BUFFER_BYTES_MAX,331	.period_bytes_min	= SIU_PERIOD_BYTES_MIN,332	.period_bytes_max	= SIU_PERIOD_BYTES_MAX,333	.periods_min		= SIU_PERIODS_MIN,334	.periods_max		= SIU_PERIODS_MAX,335};336 337static int siu_dai_info_volume(struct snd_kcontrol *kctrl,338			       struct snd_ctl_elem_info *uinfo)339{340	struct siu_port *port_info = snd_kcontrol_chip(kctrl);341 342	dev_dbg(port_info->pcm->card->dev, "%s\n", __func__);343 344	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;345	uinfo->count = 2;346	uinfo->value.integer.min = 0;347	uinfo->value.integer.max = SIU_MAX_VOLUME;348 349	return 0;350}351 352static int siu_dai_get_volume(struct snd_kcontrol *kctrl,353			      struct snd_ctl_elem_value *ucontrol)354{355	struct siu_port *port_info = snd_kcontrol_chip(kctrl);356	struct device *dev = port_info->pcm->card->dev;357	u32 vol;358 359	dev_dbg(dev, "%s\n", __func__);360 361	switch (kctrl->private_value) {362	case VOLUME_PLAYBACK:363		/* Playback is always on port 0 */364		vol = port_info->playback.volume;365		ucontrol->value.integer.value[0] = vol & 0xffff;366		ucontrol->value.integer.value[1] = vol >> 16 & 0xffff;367		break;368	case VOLUME_CAPTURE:369		/* Capture is always on port 1 */370		vol = port_info->capture.volume;371		ucontrol->value.integer.value[0] = vol & 0xffff;372		ucontrol->value.integer.value[1] = vol >> 16 & 0xffff;373		break;374	default:375		dev_err(dev, "%s() invalid private_value=%ld\n",376			__func__, kctrl->private_value);377		return -EINVAL;378	}379 380	return 0;381}382 383static int siu_dai_put_volume(struct snd_kcontrol *kctrl,384			      struct snd_ctl_elem_value *ucontrol)385{386	struct siu_port *port_info = snd_kcontrol_chip(kctrl);387	struct device *dev = port_info->pcm->card->dev;388	struct siu_info *info = siu_i2s_data;389	u32 __iomem *base = info->reg;390	u32 new_vol;391	u32 cur_vol;392 393	dev_dbg(dev, "%s\n", __func__);394 395	if (ucontrol->value.integer.value[0] < 0 ||396	    ucontrol->value.integer.value[0] > SIU_MAX_VOLUME ||397	    ucontrol->value.integer.value[1] < 0 ||398	    ucontrol->value.integer.value[1] > SIU_MAX_VOLUME)399		return -EINVAL;400 401	new_vol = ucontrol->value.integer.value[0] |402		ucontrol->value.integer.value[1] << 16;403 404	/* See comment above - DSP firmware implementation */405	switch (kctrl->private_value) {406	case VOLUME_PLAYBACK:407		/* Playback is always on port 0 */408		cur_vol = port_info->playback.volume;409		siu_write32(base + SIU_SBDVCA, new_vol);410		port_info->playback.volume = new_vol;411		break;412	case VOLUME_CAPTURE:413		/* Capture is always on port 1 */414		cur_vol = port_info->capture.volume;415		siu_write32(base + SIU_SBDVCB, new_vol);416		port_info->capture.volume = new_vol;417		break;418	default:419		dev_err(dev, "%s() invalid private_value=%ld\n",420			__func__, kctrl->private_value);421		return -EINVAL;422	}423 424	if (cur_vol != new_vol)425		return 1;426 427	return 0;428}429 430static const struct snd_kcontrol_new playback_controls = {431	.iface		= SNDRV_CTL_ELEM_IFACE_MIXER,432	.name		= "PCM Playback Volume",433	.index		= 0,434	.info		= siu_dai_info_volume,435	.get		= siu_dai_get_volume,436	.put		= siu_dai_put_volume,437	.private_value	= VOLUME_PLAYBACK,438};439 440static const struct snd_kcontrol_new capture_controls = {441	.iface		= SNDRV_CTL_ELEM_IFACE_MIXER,442	.name		= "PCM Capture Volume",443	.index		= 0,444	.info		= siu_dai_info_volume,445	.get		= siu_dai_get_volume,446	.put		= siu_dai_put_volume,447	.private_value	= VOLUME_CAPTURE,448};449 450int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card)451{452	struct device *dev = card->dev;453	struct snd_kcontrol *kctrl;454	int ret;455 456	*port_info = kzalloc(sizeof(**port_info), GFP_KERNEL);457	if (!*port_info)458		return -ENOMEM;459 460	dev_dbg(dev, "%s: port #%d@%p\n", __func__, port, *port_info);461 462	(*port_info)->playback.volume = DFLT_VOLUME_LEVEL;463	(*port_info)->capture.volume = DFLT_VOLUME_LEVEL;464 465	/*466	 * Add mixer support. The SPB is used to change the volume. Both467	 * ports use the same SPB. Therefore, we only register one468	 * control instance since it will be used by both channels.469	 * In error case we continue without controls.470	 */471	kctrl = snd_ctl_new1(&playback_controls, *port_info);472	ret = snd_ctl_add(card, kctrl);473	if (ret < 0)474		dev_err(dev,475			"failed to add playback controls %p port=%d err=%d\n",476			kctrl, port, ret);477 478	kctrl = snd_ctl_new1(&capture_controls, *port_info);479	ret = snd_ctl_add(card, kctrl);480	if (ret < 0)481		dev_err(dev,482			"failed to add capture controls %p port=%d err=%d\n",483			kctrl, port, ret);484 485	return 0;486}487 488void siu_free_port(struct siu_port *port_info)489{490	kfree(port_info);491}492 493static int siu_dai_startup(struct snd_pcm_substream *substream,494			   struct snd_soc_dai *dai)495{496	struct siu_info *info = snd_soc_dai_get_drvdata(dai);497	struct snd_pcm_runtime *rt = substream->runtime;498	struct siu_port	*port_info = siu_port_info(substream);499	int ret;500 501	dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__,502		info->port_id, port_info);503 504	snd_soc_set_runtime_hwparams(substream, &siu_dai_pcm_hw);505 506	ret = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);507	if (unlikely(ret < 0))508		return ret;509 510	siu_dai_start(port_info);511 512	return 0;513}514 515static void siu_dai_shutdown(struct snd_pcm_substream *substream,516			     struct snd_soc_dai *dai)517{518	struct siu_info *info = snd_soc_dai_get_drvdata(dai);519	struct siu_port	*port_info = siu_port_info(substream);520 521	dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__,522		info->port_id, port_info);523 524	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)525		port_info->play_cap &= ~PLAYBACK_ENABLED;526	else527		port_info->play_cap &= ~CAPTURE_ENABLED;528 529	/* Stop the siu if the other stream is not using it */530	if (!port_info->play_cap) {531		/* during stmread or stmwrite ? */532		if (WARN_ON(port_info->playback.rw_flg || port_info->capture.rw_flg))533			return;534		siu_dai_spbstop(port_info);535		siu_dai_stop(port_info);536	}537}538 539/* PCM part of siu_dai_playback_prepare() / siu_dai_capture_prepare() */540static int siu_dai_prepare(struct snd_pcm_substream *substream,541			   struct snd_soc_dai *dai)542{543	struct siu_info *info = snd_soc_dai_get_drvdata(dai);544	struct snd_pcm_runtime *rt = substream->runtime;545	struct siu_port *port_info = siu_port_info(substream);546	struct siu_stream *siu_stream;547	int self, ret;548 549	dev_dbg(substream->pcm->card->dev,550		"%s: port %d, active streams %lx, %d channels\n",551		__func__, info->port_id, port_info->play_cap, rt->channels);552 553	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {554		self = PLAYBACK_ENABLED;555		siu_stream = &port_info->playback;556	} else {557		self = CAPTURE_ENABLED;558		siu_stream = &port_info->capture;559	}560 561	/* Set up the siu if not already done */562	if (!port_info->play_cap) {563		siu_stream->rw_flg = 0;	/* stream-data transfer flag */564 565		siu_dai_spbAselect(port_info);566		siu_dai_spbBselect(port_info);567 568		siu_dai_open(siu_stream);569 570		siu_dai_pcmdatapack(siu_stream);571 572		ret = siu_dai_spbstart(port_info);573		if (ret < 0)574			goto fail;575	} else {576		ret = 0;577	}578 579	port_info->play_cap |= self;580 581fail:582	return ret;583}584 585/*586 * SIU can set bus format to I2S / PCM / SPDIF independently for playback and587 * capture, however, the current API sets the bus format globally for a DAI.588 */589static int siu_dai_set_fmt(struct snd_soc_dai *dai,590			   unsigned int fmt)591{592	struct siu_info *info = snd_soc_dai_get_drvdata(dai);593	u32 __iomem *base = info->reg;594	u32 ifctl;595 596	dev_dbg(dai->dev, "%s: fmt 0x%x on port %d\n",597		__func__, fmt, info->port_id);598 599	if (info->port_id < 0)600		return -ENODEV;601 602	/* Here select between I2S / PCM / SPDIF */603	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {604	case SND_SOC_DAIFMT_I2S:605		ifctl = siu_flags[info->port_id].playback.i2s |606			siu_flags[info->port_id].capture.i2s;607		break;608	case SND_SOC_DAIFMT_LEFT_J:609		ifctl = siu_flags[info->port_id].playback.pcm |610			siu_flags[info->port_id].capture.pcm;611		break;612	/* SPDIF disabled - see comment at the top */613	default:614		return -EINVAL;615	}616 617	ifctl |= ~(siu_flags[info->port_id].playback.mask |618		   siu_flags[info->port_id].capture.mask) &619		siu_read32(base + SIU_IFCTL);620	siu_write32(base + SIU_IFCTL, ifctl);621 622	return 0;623}624 625static int siu_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,626			      unsigned int freq, int dir)627{628	struct clk *siu_clk, *parent_clk;629	char *siu_name, *parent_name;630	int ret;631 632	if (dir != SND_SOC_CLOCK_IN)633		return -EINVAL;634 635	dev_dbg(dai->dev, "%s: using clock %d\n", __func__, clk_id);636 637	switch (clk_id) {638	case SIU_CLKA_PLL:639		siu_name = "siua_clk";640		parent_name = "pll_clk";641		break;642	case SIU_CLKA_EXT:643		siu_name = "siua_clk";644		parent_name = "siumcka_clk";645		break;646	case SIU_CLKB_PLL:647		siu_name = "siub_clk";648		parent_name = "pll_clk";649		break;650	case SIU_CLKB_EXT:651		siu_name = "siub_clk";652		parent_name = "siumckb_clk";653		break;654	default:655		return -EINVAL;656	}657 658	siu_clk = clk_get(dai->dev, siu_name);659	if (IS_ERR(siu_clk)) {660		dev_err(dai->dev, "%s: cannot get a SIU clock: %ld\n", __func__,661			PTR_ERR(siu_clk));662		return PTR_ERR(siu_clk);663	}664 665	parent_clk = clk_get(dai->dev, parent_name);666	if (IS_ERR(parent_clk)) {667		ret = PTR_ERR(parent_clk);668		dev_err(dai->dev, "cannot get a SIU clock parent: %d\n", ret);669		goto epclkget;670	}671 672	ret = clk_set_parent(siu_clk, parent_clk);673	if (ret < 0) {674		dev_err(dai->dev, "cannot reparent the SIU clock: %d\n", ret);675		goto eclksetp;676	}677 678	ret = clk_set_rate(siu_clk, freq);679	if (ret < 0)680		dev_err(dai->dev, "cannot set SIU clock rate: %d\n", ret);681 682	/* TODO: when clkdev gets reference counting we'll move these to siu_dai_shutdown() */683eclksetp:684	clk_put(parent_clk);685epclkget:686	clk_put(siu_clk);687 688	return ret;689}690 691static const struct snd_soc_dai_ops siu_dai_ops = {692	.startup	= siu_dai_startup,693	.shutdown	= siu_dai_shutdown,694	.prepare	= siu_dai_prepare,695	.set_sysclk	= siu_dai_set_sysclk,696	.set_fmt	= siu_dai_set_fmt,697};698 699static struct snd_soc_dai_driver siu_i2s_dai = {700	.name	= "siu-i2s-dai",701	.playback = {702		.channels_min = 2,703		.channels_max = 2,704		.formats = SNDRV_PCM_FMTBIT_S16,705		.rates = SNDRV_PCM_RATE_8000_48000,706	},707	.capture = {708		.channels_min = 2,709		.channels_max = 2,710		.formats = SNDRV_PCM_FMTBIT_S16,711		.rates = SNDRV_PCM_RATE_8000_48000,712	 },713	.ops = &siu_dai_ops,714};715 716static int siu_probe(struct platform_device *pdev)717{718	const struct firmware *fw_entry;719	struct resource *res, *region;720	struct siu_info *info;721	int ret;722 723	info = devm_kmalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);724	if (!info)725		return -ENOMEM;726	siu_i2s_data = info;727	info->dev = &pdev->dev;728 729	ret = request_firmware(&fw_entry, "siu_spb.bin", &pdev->dev);730	if (ret)731		return ret;732 733	/*734	 * Loaded firmware is "const" - read only, but we have to modify it in735	 * snd_siu_sh7343_spbAselect() and snd_siu_sh7343_spbBselect()736	 */737	memcpy(&info->fw, fw_entry->data, fw_entry->size);738 739	release_firmware(fw_entry);740 741	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);742	if (!res)743		return -ENODEV;744 745	region = devm_request_mem_region(&pdev->dev, res->start,746					 resource_size(res), pdev->name);747	if (!region) {748		dev_err(&pdev->dev, "SIU region already claimed\n");749		return -EBUSY;750	}751 752	info->pram = devm_ioremap(&pdev->dev, res->start, PRAM_SIZE);753	if (!info->pram)754		return -ENOMEM;755	info->xram = devm_ioremap(&pdev->dev, res->start + XRAM_OFFSET,756				  XRAM_SIZE);757	if (!info->xram)758		return -ENOMEM;759	info->yram = devm_ioremap(&pdev->dev, res->start + YRAM_OFFSET,760				  YRAM_SIZE);761	if (!info->yram)762		return -ENOMEM;763	info->reg = devm_ioremap(&pdev->dev, res->start + REG_OFFSET,764			    resource_size(res) - REG_OFFSET);765	if (!info->reg)766		return -ENOMEM;767 768	dev_set_drvdata(&pdev->dev, info);769 770	/* register using ARRAY version so we can keep dai name */771	ret = devm_snd_soc_register_component(&pdev->dev, &siu_component,772					      &siu_i2s_dai, 1);773	if (ret < 0)774		return ret;775 776	pm_runtime_enable(&pdev->dev);777 778	return 0;779}780 781static void siu_remove(struct platform_device *pdev)782{783	pm_runtime_disable(&pdev->dev);784}785 786static struct platform_driver siu_driver = {787	.driver 	= {788		.name	= "siu-pcm-audio",789	},790	.probe		= siu_probe,791	.remove		= siu_remove,792};793 794module_platform_driver(siu_driver);795 796MODULE_AUTHOR("Carlos Munoz <carlos@kenati.com>");797MODULE_DESCRIPTION("ALSA SoC SH7722 SIU driver");798MODULE_LICENSE("GPL");799 800MODULE_FIRMWARE("siu_spb.bin");801