xref: /rk3399_rockchip-uboot/drivers/sound/rockchip-sound.c (revision 0e00a84cdedf7a1949486746225b35984b351eca)
15b9c2cccSSugar Zhang // SPDX-License-Identifier:     GPL-2.0+
25b9c2cccSSugar Zhang /*
35b9c2cccSSugar Zhang  * (C) Copyright 2018 Rockchip Electronics Co., Ltd
45b9c2cccSSugar Zhang  */
55b9c2cccSSugar Zhang 
65b9c2cccSSugar Zhang #include <dm.h>
75b9c2cccSSugar Zhang #include <malloc.h>
85b9c2cccSSugar Zhang #include <common.h>
95b9c2cccSSugar Zhang #include <asm/io.h>
10*0e00a84cSMasahiro Yamada #include <linux/libfdt.h>
115b9c2cccSSugar Zhang #include <fdtdec.h>
125b9c2cccSSugar Zhang #include <i2s.h>
135b9c2cccSSugar Zhang #include <sound.h>
145b9c2cccSSugar Zhang #include <asm/arch-rockchip/resource_img.h>
155b9c2cccSSugar Zhang 
165b9c2cccSSugar Zhang #define WAV_SIZE		(5 * 1024 * 1024) /* BYTE */
175b9c2cccSSugar Zhang #define SAMPLERATE		44100
185b9c2cccSSugar Zhang 
195b9c2cccSSugar Zhang static struct udevice *i2s_dev, *codec_dev;
205b9c2cccSSugar Zhang 
load_audio_wav(void * buf,const char * wav_name,int size)215b9c2cccSSugar Zhang static int load_audio_wav(void *buf, const char *wav_name, int size)
225b9c2cccSSugar Zhang {
235b9c2cccSSugar Zhang 	int ret = 0;
245b9c2cccSSugar Zhang #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
255b9c2cccSSugar Zhang 	ret = rockchip_read_resource_file(buf, wav_name, 0, size);
265b9c2cccSSugar Zhang #endif
275b9c2cccSSugar Zhang 
285b9c2cccSSugar Zhang 	return ret;
295b9c2cccSSugar Zhang }
305b9c2cccSSugar Zhang 
sound_hw_params(struct udevice * dev,unsigned int samplerate,unsigned int fmt,unsigned int channels)315b9c2cccSSugar Zhang static int sound_hw_params(struct udevice *dev, unsigned int samplerate,
325b9c2cccSSugar Zhang 			   unsigned int fmt, unsigned int channels)
335b9c2cccSSugar Zhang {
345b9c2cccSSugar Zhang 	const struct snd_soc_dai_ops *ops = dev_get_driver_ops(dev);
355b9c2cccSSugar Zhang 
365b9c2cccSSugar Zhang 	if (!ops || !ops->hw_params)
375b9c2cccSSugar Zhang 		return -ENOTSUPP;
385b9c2cccSSugar Zhang 
395b9c2cccSSugar Zhang 	return ops->hw_params(dev, samplerate, fmt, channels);
405b9c2cccSSugar Zhang }
415b9c2cccSSugar Zhang 
sound_startup(struct udevice * dev)425b9c2cccSSugar Zhang static int sound_startup(struct udevice *dev)
435b9c2cccSSugar Zhang {
445b9c2cccSSugar Zhang 	const struct snd_soc_dai_ops *ops = dev_get_driver_ops(dev);
455b9c2cccSSugar Zhang 
465b9c2cccSSugar Zhang 	if (!ops || !ops->startup)
475b9c2cccSSugar Zhang 		return -ENOTSUPP;
485b9c2cccSSugar Zhang 
495b9c2cccSSugar Zhang 	return ops->startup(dev);
505b9c2cccSSugar Zhang }
515b9c2cccSSugar Zhang 
sound_set_sysclk(struct udevice * dev,unsigned int freq)525b9c2cccSSugar Zhang static int sound_set_sysclk(struct udevice *dev, unsigned int freq)
535b9c2cccSSugar Zhang {
545b9c2cccSSugar Zhang 	const struct snd_soc_dai_ops *ops = dev_get_driver_ops(dev);
555b9c2cccSSugar Zhang 
565b9c2cccSSugar Zhang 	if (!ops || !ops->set_sysclk)
575b9c2cccSSugar Zhang 		return -ENOTSUPP;
585b9c2cccSSugar Zhang 
595b9c2cccSSugar Zhang 	return ops->set_sysclk(dev, freq);
605b9c2cccSSugar Zhang }
615b9c2cccSSugar Zhang 
sound_init(const void * blob)625b9c2cccSSugar Zhang int sound_init(const void *blob)
635b9c2cccSSugar Zhang {
645b9c2cccSSugar Zhang 	int ret;
655b9c2cccSSugar Zhang 
665b9c2cccSSugar Zhang 	ret = uclass_get_device(UCLASS_I2S, 0, &i2s_dev);
675b9c2cccSSugar Zhang 	if (ret) {
685b9c2cccSSugar Zhang 		if (ret != -ENODEV) {
695b9c2cccSSugar Zhang 			printf("Get i2s device failed: %d\n", ret);
705b9c2cccSSugar Zhang 			return ret;
715b9c2cccSSugar Zhang 		}
725b9c2cccSSugar Zhang 		return 0;
735b9c2cccSSugar Zhang 	}
745b9c2cccSSugar Zhang 
755b9c2cccSSugar Zhang 	ret = uclass_get_device(UCLASS_CODEC, 0, &codec_dev);
765b9c2cccSSugar Zhang 	if (ret) {
775b9c2cccSSugar Zhang 		if (ret != -ENODEV) {
785b9c2cccSSugar Zhang 			printf("Get codec device failed: %d\n", ret);
795b9c2cccSSugar Zhang 			return ret;
805b9c2cccSSugar Zhang 		}
815b9c2cccSSugar Zhang 		return 0;
825b9c2cccSSugar Zhang 	}
835b9c2cccSSugar Zhang 
845b9c2cccSSugar Zhang 	sound_set_sysclk(i2s_dev, SAMPLERATE * 256);
855b9c2cccSSugar Zhang 	sound_hw_params(i2s_dev, SAMPLERATE, 16, 2);
865b9c2cccSSugar Zhang 	sound_hw_params(codec_dev, SAMPLERATE, 16, 2);
875b9c2cccSSugar Zhang 	sound_startup(i2s_dev);
885b9c2cccSSugar Zhang 	sound_startup(codec_dev);
895b9c2cccSSugar Zhang 
905b9c2cccSSugar Zhang 	return ret;
915b9c2cccSSugar Zhang }
925b9c2cccSSugar Zhang 
_sound_play(struct udevice * dev,unsigned int * data,unsigned long data_size)935b9c2cccSSugar Zhang static int _sound_play(struct udevice *dev, unsigned int *data,
945b9c2cccSSugar Zhang 		       unsigned long data_size)
955b9c2cccSSugar Zhang {
965b9c2cccSSugar Zhang 	const struct snd_soc_dai_ops *ops = dev_get_driver_ops(dev);
975b9c2cccSSugar Zhang 
985b9c2cccSSugar Zhang 	if (!ops || !ops->transfer)
995b9c2cccSSugar Zhang 		return -ENOTSUPP;
1005b9c2cccSSugar Zhang 
1015b9c2cccSSugar Zhang 	return ops->transfer(dev, data, data_size);
1025b9c2cccSSugar Zhang }
1035b9c2cccSSugar Zhang 
sound_play(u32 msec,u32 frequency)1045b9c2cccSSugar Zhang int sound_play(u32 msec, u32 frequency)
1055b9c2cccSSugar Zhang {
1065b9c2cccSSugar Zhang 	unsigned int *buf;
1075b9c2cccSSugar Zhang 	unsigned long buf_size;
1085b9c2cccSSugar Zhang 	unsigned int ret = 0;
1095b9c2cccSSugar Zhang 
1105b9c2cccSSugar Zhang 	buf_size = WAV_SIZE;
1115b9c2cccSSugar Zhang 
1125b9c2cccSSugar Zhang 	buf = malloc(buf_size);
1135b9c2cccSSugar Zhang 	if (!buf) {
1145b9c2cccSSugar Zhang 		debug("%s: buf malloc failed\n", __func__);
1155b9c2cccSSugar Zhang 		return -ENOMEM;
1165b9c2cccSSugar Zhang 	}
1175b9c2cccSSugar Zhang 	ret = load_audio_wav(buf, "boot.wav", buf_size);
1185b9c2cccSSugar Zhang 	/* if boot.wav not find, use sound_create_square_wave */
1195b9c2cccSSugar Zhang 	if (ret <= 0)
1205b9c2cccSSugar Zhang 		sound_create_square_wave((unsigned short *)buf,
1215b9c2cccSSugar Zhang 					 buf_size / sizeof(unsigned short),
1225b9c2cccSSugar Zhang 					 frequency);
1235b9c2cccSSugar Zhang 
1245b9c2cccSSugar Zhang 	ret = _sound_play(i2s_dev, buf, (buf_size / sizeof(int)));
1255b9c2cccSSugar Zhang 	free(buf);
1265b9c2cccSSugar Zhang 
1275b9c2cccSSugar Zhang 	return ret;
1285b9c2cccSSugar Zhang }
129