From ee53494d0e39b110bbfa4df828c0b70131013014 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 3 Dec 2018 04:37:20 -0700 Subject: dm: sound: Rename en_sound_codec to sound_codec The en_ prefix is confusing and not needed. Drop it. Signed-off-by: Simon Glass --- include/sound.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/sound.h b/include/sound.h index 77bfe6a93b2..149e12dbc60 100644 --- a/include/sound.h +++ b/include/sound.h @@ -8,7 +8,7 @@ #define __SOUND_H__ /* sound codec enum */ -enum en_sound_codec { +enum sound_codec { CODEC_WM_8994, CODEC_WM_8995, CODEC_MAX_98095, @@ -25,7 +25,7 @@ enum sound_compat { struct sound_codec_info { int i2c_bus; int i2c_dev_addr; - enum en_sound_codec codec_type; + enum sound_codec codec_type; }; /* -- cgit v1.3.1 From ccf0425e3208cbc17f08411651c1197da3b38f3a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 3 Dec 2018 04:37:22 -0700 Subject: dm: sound: samsung: Rename i2stx_info to samsung_i2s_priv This struct is only used by the Samsung I2C driver and should move into that driver. For now, rename it so it is clear that is driver-private info. Signed-off-by: Simon Glass --- drivers/sound/samsung-i2s.c | 6 +++--- drivers/sound/sound-i2s.c | 10 +++++----- include/i2s.h | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/drivers/sound/samsung-i2s.c b/drivers/sound/samsung-i2s.c index 8f5cd191a2b..7f4388137a5 100644 --- a/drivers/sound/samsung-i2s.c +++ b/drivers/sound/samsung-i2s.c @@ -255,8 +255,8 @@ static int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc) return 0; } -int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned int *data, - unsigned long data_size) +int i2s_transfer_tx_data(struct samsung_i2s_priv *pi2s_tx, unsigned int *data, + unsigned long data_size) { int i; int start; @@ -293,7 +293,7 @@ int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned int *data, return 0; } -int i2s_tx_init(struct i2stx_info *pi2s_tx) +int i2s_tx_init(struct samsung_i2s_priv *pi2s_tx) { int ret; struct i2s_reg *i2s_reg = diff --git a/drivers/sound/sound-i2s.c b/drivers/sound/sound-i2s.c index f0f0b79bc52..106842a23db 100644 --- a/drivers/sound/sound-i2s.c +++ b/drivers/sound/sound-i2s.c @@ -20,15 +20,15 @@ #define SOUND_400_HZ 400 #define SOUND_BITS_IN_BYTE 8 -static struct i2stx_info g_i2stx_pri; +static struct samsung_i2s_priv g_i2stx_pri; /* * get_sound_i2s_values gets values for i2s parameters * - * @param i2stx_info i2s transmitter transfer param structure + * @param samsung_i2s_priv i2s transmitter transfer param structure * @param blob FDT blob if enabled else NULL */ -static int get_sound_i2s_values(struct i2stx_info *i2s, const void *blob) +static int get_sound_i2s_values(struct samsung_i2s_priv *i2s, const void *blob) { int node; int error = 0; @@ -97,7 +97,7 @@ static int get_sound_i2s_values(struct i2stx_info *i2s, const void *blob) * @param pi2s_tx i2s parameters required by codec * @return int value, 0 for success */ -static int codec_init(const void *blob, struct i2stx_info *pi2s_tx) +static int codec_init(const void *blob, struct samsung_i2s_priv *pi2s_tx) { int ret; const char *codectype; @@ -145,7 +145,7 @@ static int codec_init(const void *blob, struct i2stx_info *pi2s_tx) int sound_init(const void *blob) { int ret; - struct i2stx_info *pi2s_tx = &g_i2stx_pri; + struct samsung_i2s_priv *pi2s_tx = &g_i2stx_pri; /* Get the I2S Values */ if (get_sound_i2s_values(pi2s_tx, blob) < 0) { diff --git a/include/i2s.h b/include/i2s.h index e6d45ec26d7..800473abd9c 100644 --- a/include/i2s.h +++ b/include/i2s.h @@ -76,7 +76,7 @@ struct i2s_reg { }; /* This structure stores the i2s related information */ -struct i2stx_info { +struct samsung_i2s_priv { unsigned int rfs; /* LR clock frame size */ unsigned int bfs; /* Bit slock frame size */ unsigned int audio_pll_clk; /* Audio pll frequency in Hz */ @@ -96,8 +96,8 @@ struct i2stx_info { * * @return int value 0 for success, -1 in case of error */ -int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned *data, - unsigned long data_size); +int i2s_transfer_tx_data(struct samsung_i2s_priv *pi2s_tx, uint *data, + unsigned long data_size); /* * Initialise i2s transmiter @@ -106,6 +106,6 @@ int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned *data, * * @return int value 0 for success, -1 in case of error */ -int i2s_tx_init(struct i2stx_info *pi2s_tx); +int i2s_tx_init(struct samsung_i2s_priv *pi2s_tx); #endif /* __I2S_H__ */ -- cgit v1.3.1 From 7153ad834f72da49eadf8b5e66d593f88514be7c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 3 Dec 2018 04:37:23 -0700 Subject: dm: sound: Drop codec_type This field is not really used. It is always set to a known value. Drop it to simplify the code. Signed-off-by: Simon Glass --- drivers/sound/max98095.c | 14 -------------- drivers/sound/wm8994.c | 10 ---------- include/sound.h | 9 --------- 3 files changed, 33 deletions(-) (limited to 'include') diff --git a/drivers/sound/max98095.c b/drivers/sound/max98095.c index d05c261a399..efaaeb8f3b8 100644 --- a/drivers/sound/max98095.c +++ b/drivers/sound/max98095.c @@ -24,12 +24,7 @@ #include "i2s.h" #include "max98095.h" -enum max98095_type { - MAX98095, -}; - struct max98095_priv { - enum max98095_type devtype; unsigned int sysclk; unsigned int rate; unsigned int fmt; @@ -484,14 +479,6 @@ static int max98095_do_init(struct sound_codec_info *pcodec_info, /* shift the device address by 1 for 7 bit addressing */ g_max98095_i2c_dev_addr = pcodec_info->i2c_dev_addr >> 1; - if (pcodec_info->codec_type == CODEC_MAX_98095) { - g_max98095_info.devtype = MAX98095; - } else { - debug("%s: Codec id [%d] not defined\n", __func__, - pcodec_info->codec_type); - return -1; - } - ret = max98095_device_init(&g_max98095_info, aif_id); if (ret < 0) { debug("%s: max98095 codec chip init failed\n", __func__); @@ -555,7 +542,6 @@ static int get_max98095_codec_values(struct sound_codec_info *pcodec_info, debug("%s: Unknown compat id %d\n", __func__, compat); return -1; } - pcodec_info->codec_type = CODEC_MAX_98095; if (error == -1) { debug("fail to get max98095 codec node properties\n"); return -1; diff --git a/drivers/sound/wm8994.c b/drivers/sound/wm8994.c index 34bc4eb516f..2e84e92a2e0 100644 --- a/drivers/sound/wm8994.c +++ b/drivers/sound/wm8994.c @@ -847,8 +847,6 @@ static int get_codec_values(struct sound_codec_info *pcodec_info, return -1; } - pcodec_info->codec_type = CODEC_WM_8994; - if (error == -1) { debug("fail to get wm8994 codec node properties\n"); return -1; @@ -875,14 +873,6 @@ int wm8994_init(const void *blob, enum en_audio_interface aif_id, g_wm8994_i2c_dev_addr = pcodec_info->i2c_dev_addr; wm8994_i2c_init(pcodec_info->i2c_bus); - if (pcodec_info->codec_type == CODEC_WM_8994) { - g_wm8994_info.type = WM8994; - } else { - debug("%s: Codec id [%d] not defined\n", __func__, - pcodec_info->codec_type); - return -1; - } - ret = wm8994_device_init(&g_wm8994_info, aif_id); if (ret < 0) { debug("%s: wm8994 codec chip init failed\n", __func__); diff --git a/include/sound.h b/include/sound.h index 149e12dbc60..c4ac3193fe7 100644 --- a/include/sound.h +++ b/include/sound.h @@ -7,14 +7,6 @@ #ifndef __SOUND_H__ #define __SOUND_H__ -/* sound codec enum */ -enum sound_codec { - CODEC_WM_8994, - CODEC_WM_8995, - CODEC_MAX_98095, - CODEC_MAX -}; - /* sound codec enum */ enum sound_compat { AUDIO_COMPAT_SPI, @@ -25,7 +17,6 @@ enum sound_compat { struct sound_codec_info { int i2c_bus; int i2c_dev_addr; - enum sound_codec codec_type; }; /* -- cgit v1.3.1 From 45863db5a97360b6843a0488621342819e9a6e62 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 10 Dec 2018 10:37:32 -0700 Subject: dm: sound: Rename samsung_i2s_priv to i2s_uc_priv This structure contains information that is likely needed by any i2s driver so it seems useful to attach it to the (forthcoming) i2c uclass. For now, just rename it. Signed-off-by: Simon Glass --- drivers/sound/samsung-i2s.c | 4 ++-- drivers/sound/sound-i2s.c | 10 +++++----- include/i2s.h | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/sound/samsung-i2s.c b/drivers/sound/samsung-i2s.c index c07d3cdb4c8..5cd585808ab 100644 --- a/drivers/sound/samsung-i2s.c +++ b/drivers/sound/samsung-i2s.c @@ -255,7 +255,7 @@ static int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc) return 0; } -int i2s_transfer_tx_data(struct samsung_i2s_priv *pi2s_tx, unsigned int *data, +int i2s_transfer_tx_data(struct i2s_uc_priv *pi2s_tx, unsigned int *data, unsigned long data_size) { int i; @@ -293,7 +293,7 @@ int i2s_transfer_tx_data(struct samsung_i2s_priv *pi2s_tx, unsigned int *data, return 0; } -int i2s_tx_init(struct samsung_i2s_priv *pi2s_tx) +int i2s_tx_init(struct i2s_uc_priv *pi2s_tx) { int ret; struct i2s_reg *i2s_reg = diff --git a/drivers/sound/sound-i2s.c b/drivers/sound/sound-i2s.c index 106842a23db..ed130750b2e 100644 --- a/drivers/sound/sound-i2s.c +++ b/drivers/sound/sound-i2s.c @@ -20,15 +20,15 @@ #define SOUND_400_HZ 400 #define SOUND_BITS_IN_BYTE 8 -static struct samsung_i2s_priv g_i2stx_pri; +static struct i2s_uc_priv g_i2stx_pri; /* * get_sound_i2s_values gets values for i2s parameters * - * @param samsung_i2s_priv i2s transmitter transfer param structure + * @param i2s_uc_priv i2s transmitter transfer param structure * @param blob FDT blob if enabled else NULL */ -static int get_sound_i2s_values(struct samsung_i2s_priv *i2s, const void *blob) +static int get_sound_i2s_values(struct i2s_uc_priv *i2s, const void *blob) { int node; int error = 0; @@ -97,7 +97,7 @@ static int get_sound_i2s_values(struct samsung_i2s_priv *i2s, const void *blob) * @param pi2s_tx i2s parameters required by codec * @return int value, 0 for success */ -static int codec_init(const void *blob, struct samsung_i2s_priv *pi2s_tx) +static int codec_init(const void *blob, struct i2s_uc_priv *pi2s_tx) { int ret; const char *codectype; @@ -145,7 +145,7 @@ static int codec_init(const void *blob, struct samsung_i2s_priv *pi2s_tx) int sound_init(const void *blob) { int ret; - struct samsung_i2s_priv *pi2s_tx = &g_i2stx_pri; + struct i2s_uc_priv *pi2s_tx = &g_i2stx_pri; /* Get the I2S Values */ if (get_sound_i2s_values(pi2s_tx, blob) < 0) { diff --git a/include/i2s.h b/include/i2s.h index 800473abd9c..f23862ca040 100644 --- a/include/i2s.h +++ b/include/i2s.h @@ -76,7 +76,7 @@ struct i2s_reg { }; /* This structure stores the i2s related information */ -struct samsung_i2s_priv { +struct i2s_uc_priv { unsigned int rfs; /* LR clock frame size */ unsigned int bfs; /* Bit slock frame size */ unsigned int audio_pll_clk; /* Audio pll frequency in Hz */ @@ -96,7 +96,7 @@ struct samsung_i2s_priv { * * @return int value 0 for success, -1 in case of error */ -int i2s_transfer_tx_data(struct samsung_i2s_priv *pi2s_tx, uint *data, +int i2s_transfer_tx_data(struct i2s_uc_priv *pi2s_tx, unsigned int *data, unsigned long data_size); /* @@ -106,6 +106,6 @@ int i2s_transfer_tx_data(struct samsung_i2s_priv *pi2s_tx, uint *data, * * @return int value 0 for success, -1 in case of error */ -int i2s_tx_init(struct samsung_i2s_priv *pi2s_tx); +int i2s_tx_init(struct i2s_uc_priv *pi2s_tx); #endif /* __I2S_H__ */ -- cgit v1.3.1 From ce6d99a056ebc9ad329521ca3660f6cb298a7666 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 10 Dec 2018 10:37:33 -0700 Subject: dm: sound: Create a uclass for audio codecs An audio codec provides a way to convert digital data to sound and vice versa. Add a simple uclass which just supports setting the parameters for the codec. Signed-off-by: Simon Glass --- arch/sandbox/dts/test.dts | 7 +++++- arch/sandbox/include/asm/test.h | 10 ++++++++ drivers/sound/Makefile | 1 + drivers/sound/codec-uclass.c | 26 +++++++++++++++++++ drivers/sound/sandbox.c | 55 +++++++++++++++++++++++++++++++++++++++++ include/audio_codec.h | 48 +++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + test/dm/Makefile | 1 + test/dm/audio.c | 34 +++++++++++++++++++++++++ 9 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 drivers/sound/codec-uclass.c create mode 100644 include/audio_codec.h create mode 100644 test/dm/audio.c (limited to 'include') diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 6b1c2692baa..9ced5beee89 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -42,7 +42,12 @@ osd0 = "/osd"; }; - cros_ec: cros-ec { + audio: audio-codec { + compatible = "sandbox,audio-codec"; + #sound-dai-cells = <1>; + }; + + cros_ec: cros-ec { reg = <0 0>; compatible = "google,cros-ec-sandbox"; diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index 5e818392959..f70e0d84177 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -121,4 +121,14 @@ int sandbox_pwm_get_config(struct udevice *dev, uint channel, uint *period_nsp, */ void sandbox_sf_set_block_protect(struct udevice *dev, int bp_mask); +/** + * sandbox_get_codec_params() - Read back codec parameters + * + * This reads back the parameters set by audio_codec_set_params() for the + * sandbox audio driver. Arguments are as for that function. + */ +void sandbox_get_codec_params(struct udevice *dev, int *interfacep, int *ratep, + int *mclk_freqp, int *bits_per_samplep, + uint *channelsp); + #endif diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index 696c5aecbe9..ae5fabed846 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -4,6 +4,7 @@ # R. Chandrasekar obj-$(CONFIG_SOUND) += sound.o +obj-$(CONFIG_DM_SOUND) += codec-uclass.o obj-$(CONFIG_I2S) += sound-i2s.o obj-$(CONFIG_I2S_SAMSUNG) += samsung-i2s.o obj-$(CONFIG_SOUND_SANDBOX) += sandbox.o diff --git a/drivers/sound/codec-uclass.c b/drivers/sound/codec-uclass.c new file mode 100644 index 00000000000..1ec77acfc1c --- /dev/null +++ b/drivers/sound/codec-uclass.c @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include + +int audio_codec_set_params(struct udevice *dev, int interface, int rate, + int mclk_freq, int bits_per_sample, uint channels) +{ + struct audio_codec_ops *ops = audio_codec_get_ops(dev); + + if (!ops->set_params) + return -ENOSYS; + + return ops->set_params(dev, interface, rate, mclk_freq, bits_per_sample, + channels); +} + +UCLASS_DRIVER(audio_codec) = { + .id = UCLASS_AUDIO_CODEC, + .name = "audio-codec", +}; diff --git a/drivers/sound/sandbox.c b/drivers/sound/sandbox.c index 94eff542824..d24eb9ae9ce 100644 --- a/drivers/sound/sandbox.c +++ b/drivers/sound/sandbox.c @@ -4,9 +4,19 @@ */ #include +#include +#include #include #include +struct sandbox_codec_priv { + int interface; + int rate; + int mclk_freq; + int bits_per_sample; + uint channels; +}; + int sound_play(uint32_t msec, uint32_t frequency) { sandbox_sdl_sound_start(frequency); @@ -20,3 +30,48 @@ int sound_init(const void *blob) { return sandbox_sdl_sound_init(); } + +void sandbox_get_codec_params(struct udevice *dev, int *interfacep, int *ratep, + int *mclk_freqp, int *bits_per_samplep, + uint *channelsp) +{ + struct sandbox_codec_priv *priv = dev_get_priv(dev); + + *interfacep = priv->interface; + *ratep = priv->rate; + *mclk_freqp = priv->mclk_freq; + *bits_per_samplep = priv->bits_per_sample; + *channelsp = priv->channels; +} + +static int sandbox_codec_set_params(struct udevice *dev, int interface, + int rate, int mclk_freq, + int bits_per_sample, uint channels) +{ + struct sandbox_codec_priv *priv = dev_get_priv(dev); + + priv->interface = interface; + priv->rate = rate; + priv->mclk_freq = mclk_freq; + priv->bits_per_sample = bits_per_sample; + priv->channels = channels; + + return 0; +} + +static const struct audio_codec_ops sandbox_codec_ops = { + .set_params = sandbox_codec_set_params, +}; + +static const struct udevice_id sandbox_codec_ids[] = { + { .compatible = "sandbox,audio-codec" }, + { } +}; + +U_BOOT_DRIVER(sandbox_codec) = { + .name = "sandbox_codec", + .id = UCLASS_AUDIO_CODEC, + .of_match = sandbox_codec_ids, + .ops = &sandbox_codec_ops, + .priv_auto_alloc_size = sizeof(struct sandbox_codec_priv), +}; diff --git a/include/audio_codec.h b/include/audio_codec.h new file mode 100644 index 00000000000..25870995469 --- /dev/null +++ b/include/audio_codec.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2018 Google LLC + * Written by Simon Glass + */ + +#ifndef __AUDIO_CODEC_H__ +#define __AUDIO_CODEC_H__ + +/* + * An audio codec turns digital data into sound with various parameters to + * control its operation. + */ + +/* Operations for sound */ +struct audio_codec_ops { + /** + * set_params() - Set audio codec parameters + * + * @dev: Sound device + * @inteface: Interface number to use on codec + * @rate: Sampling rate in Hz + * @mclk_freq: Codec clock frequency in Hz + * @bits_per_sample: Must be 16 or 24 + * @channels: Number of channels to use (1=mono, 2=stereo) + * @return 0 if OK, -ve on error + */ + int (*set_params)(struct udevice *dev, int interface, int rate, + int mclk_freq, int bits_per_sample, uint channels); +}; + +#define audio_codec_get_ops(dev) ((struct audio_codec_ops *)(dev)->driver->ops) + +/** + * audio_codec_set_params() - Set audio codec parameters + * + * @dev: Sound device + * @inteface: Interface number to use on codec + * @rate: Sampling rate in Hz + * @mclk_freq: Codec clock frequency in Hz + * @bits_per_sample: Must be 16 or 24 + * @channels: Number of channels to use (1=mono, 2=stereo) + * @return 0 if OK, -ve on error + */ +int audio_codec_set_params(struct udevice *dev, int interface, int rate, + int mclk_freq, int bits_per_sample, uint channels); + +#endif /* __AUDIO_CODEC_H__ */ diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index e960e48b855..c3c18356ab6 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -29,6 +29,7 @@ enum uclass_id { /* U-Boot uclasses start here - in alphabetical order */ UCLASS_ADC, /* Analog-to-digital converter */ UCLASS_AHCI, /* SATA disk controller */ + UCLASS_AUDIO_CODEC, /* Audio codec with control and data path */ UCLASS_AXI, /* AXI bus */ UCLASS_BLK, /* Block device */ UCLASS_BOARD, /* Device information from hardware */ diff --git a/test/dm/Makefile b/test/dm/Makefile index 2c9081e4dd6..ef450b7ed81 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_UT_DM) += test-uclass.o # subsystem you must add sandbox tests here. obj-$(CONFIG_UT_DM) += core.o ifneq ($(CONFIG_SANDBOX),) +obj-$(CONFIG_DM_SOUND) += audio.o obj-$(CONFIG_BLK) += blk.o obj-$(CONFIG_BOARD) += board.o obj-$(CONFIG_CLK) += clk.o diff --git a/test/dm/audio.c b/test/dm/audio.c new file mode 100644 index 00000000000..77c3a3625bd --- /dev/null +++ b/test/dm/audio.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include +#include + +/* Basic test of the audio codec uclass */ +static int dm_test_audio(struct unit_test_state *uts) +{ + int interface, rate, mclk_freq, bits_per_sample; + struct udevice *dev; + uint channels; + + /* check probe success */ + ut_assertok(uclass_first_device_err(UCLASS_AUDIO_CODEC, &dev)); + ut_assertok(audio_codec_set_params(dev, 1, 2, 3, 4, 5)); + sandbox_get_codec_params(dev, &interface, &rate, &mclk_freq, + &bits_per_sample, &channels); + ut_asserteq(1, interface); + ut_asserteq(2, rate); + ut_asserteq(3, mclk_freq); + ut_asserteq(4, bits_per_sample); + ut_asserteq(5, channels); + + return 0; +} +DM_TEST(dm_test_audio, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); -- cgit v1.3.1 From e96fa6c91177d0aa81119d1d24cc0aa2dd663581 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 10 Dec 2018 10:37:34 -0700 Subject: dm: sound: Create a uclass for i2s The i2s bus is commonly used with audio codecs. It provides a way to stream digital data sychronously in both directions. U-Boot only supports audio output, so this uclass is very simple, with a single tx_data() method. Add a uclass and a test for i2s. Signed-off-by: Simon Glass --- arch/sandbox/dts/test.dts | 7 ++++- arch/sandbox/include/asm/test.h | 10 +++++++ drivers/sound/Makefile | 1 + drivers/sound/i2s-uclass.c | 25 +++++++++++++++++ drivers/sound/sandbox.c | 60 ++++++++++++++++++++++++++++++++++++++++- include/dm/uclass-id.h | 1 + include/i2s.h | 32 +++++++++++++++++++--- test/dm/Makefile | 1 + test/dm/i2s.c | 32 ++++++++++++++++++++++ 9 files changed, 163 insertions(+), 6 deletions(-) create mode 100644 drivers/sound/i2s-uclass.c create mode 100644 test/dm/i2s.c (limited to 'include') diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 9ced5beee89..5c2910c583b 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -47,7 +47,7 @@ #sound-dai-cells = <1>; }; - cros_ec: cros-ec { + cros_ec: cros-ec { reg = <0 0>; compatible = "google,cros-ec-sandbox"; @@ -378,6 +378,11 @@ u-boot,dm-pre-reloc; }; + i2s: i2s { + compatible = "sandbox,i2s"; + #sound-dai-cells = <1>; + }; + misc-test { compatible = "sandbox,misc_sandbox"; }; diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index f70e0d84177..71bd50bd5bc 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -131,4 +131,14 @@ void sandbox_get_codec_params(struct udevice *dev, int *interfacep, int *ratep, int *mclk_freqp, int *bits_per_samplep, uint *channelsp); +/** + * sandbox_get_i2s_sum() - Read back the sum of the audio data so far + * + * This data is provided to the sandbox driver by the I2S tx_data() method. + * + * @dev: Device to check + * @return sum of audio data + */ +int sandbox_get_i2s_sum(struct udevice *dev); + #endif diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index ae5fabed846..4aced9d22b9 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_SOUND) += sound.o obj-$(CONFIG_DM_SOUND) += codec-uclass.o +obj-$(CONFIG_DM_SOUND) += i2s-uclass.o obj-$(CONFIG_I2S) += sound-i2s.o obj-$(CONFIG_I2S_SAMSUNG) += samsung-i2s.o obj-$(CONFIG_SOUND_SANDBOX) += sandbox.o diff --git a/drivers/sound/i2s-uclass.c b/drivers/sound/i2s-uclass.c new file mode 100644 index 00000000000..b741e3952d1 --- /dev/null +++ b/drivers/sound/i2s-uclass.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include + +int i2s_tx_data(struct udevice *dev, void *data, uint data_size) +{ + struct i2s_ops *ops = i2s_get_ops(dev); + + if (!ops->tx_data) + return -ENOSYS; + + return ops->tx_data(dev, data, data_size); +} + +UCLASS_DRIVER(i2s) = { + .id = UCLASS_I2S, + .name = "i2s", + .per_device_auto_alloc_size = sizeof(struct i2s_uc_priv), +}; diff --git a/drivers/sound/sandbox.c b/drivers/sound/sandbox.c index d24eb9ae9ce..2f7c68be0c8 100644 --- a/drivers/sound/sandbox.c +++ b/drivers/sound/sandbox.c @@ -4,8 +4,9 @@ */ #include -#include #include +#include +#include #include #include @@ -17,6 +18,10 @@ struct sandbox_codec_priv { uint channels; }; +struct sandbox_i2s_priv { + int sum; /* Use to sum the provided audio data */ +}; + int sound_play(uint32_t msec, uint32_t frequency) { sandbox_sdl_sound_start(frequency); @@ -44,6 +49,13 @@ void sandbox_get_codec_params(struct udevice *dev, int *interfacep, int *ratep, *channelsp = priv->channels; } +int sandbox_get_i2s_sum(struct udevice *dev) +{ + struct sandbox_i2s_priv *priv = dev_get_priv(dev); + + return priv->sum; +} + static int sandbox_codec_set_params(struct udevice *dev, int interface, int rate, int mclk_freq, int bits_per_sample, uint channels) @@ -59,6 +71,34 @@ static int sandbox_codec_set_params(struct udevice *dev, int interface, return 0; } +static int sandbox_i2s_tx_data(struct udevice *dev, void *data, + uint data_size) +{ + struct sandbox_i2s_priv *priv = dev_get_priv(dev); + int i; + + for (i = 0; i < data_size; i++) + priv->sum += ((uint8_t *)data)[i]; + + return 0; +} + +static int sandbox_i2s_probe(struct udevice *dev) +{ + struct i2s_uc_priv *uc_priv = dev_get_uclass_priv(dev); + + /* Use hard-coded values here */ + uc_priv->rfs = 256; + uc_priv->bfs = 32; + uc_priv->audio_pll_clk = 192000000; + uc_priv->samplingrate = 48000; + uc_priv->bitspersample = 16; + uc_priv->channels = 2; + uc_priv->id = 1; + + return 0; +} + static const struct audio_codec_ops sandbox_codec_ops = { .set_params = sandbox_codec_set_params, }; @@ -75,3 +115,21 @@ U_BOOT_DRIVER(sandbox_codec) = { .ops = &sandbox_codec_ops, .priv_auto_alloc_size = sizeof(struct sandbox_codec_priv), }; + +static const struct i2s_ops sandbox_i2s_ops = { + .tx_data = sandbox_i2s_tx_data, +}; + +static const struct udevice_id sandbox_i2s_ids[] = { + { .compatible = "sandbox,i2s" }, + { } +}; + +U_BOOT_DRIVER(sandbox_i2s) = { + .name = "sandbox_i2s", + .id = UCLASS_I2S, + .of_match = sandbox_i2s_ids, + .ops = &sandbox_i2s_ops, + .probe = sandbox_i2s_probe, + .priv_auto_alloc_size = sizeof(struct sandbox_i2s_priv), +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index c3c18356ab6..1dffb669329 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -49,6 +49,7 @@ enum uclass_id { UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_MUX, /* I2C multiplexer */ + UCLASS_I2S, /* I2S bus */ UCLASS_IDE, /* IDE device */ UCLASS_IRQ, /* Interrupt controller */ UCLASS_KEYBOARD, /* Keyboard input device */ diff --git a/include/i2s.h b/include/i2s.h index f23862ca040..28f6184811c 100644 --- a/include/i2s.h +++ b/include/i2s.h @@ -87,17 +87,41 @@ struct i2s_uc_priv { unsigned int id; /* I2S controller id */ }; +/* Operations for i2s devices */ +struct i2s_ops { + /** + * tx_data() - Transmit audio data + * + * @dev: I2C device + * @data: Data buffer to play + * @data_size: Size of data buffer in bytes + * @return 0 if OK, -ve on error + */ + int (*tx_data)(struct udevice *dev, void *data, uint data_size); +}; + +#define i2s_get_ops(dev) ((struct i2s_ops *)(dev)->driver->ops) + +/** + * i2s_tx_data() - Transmit audio data + * + * @dev: I2C device + * @data: Data buffer to play + * @data_size: Size of data buffer in bytes + * @return 0 if OK, -ve on error + */ +int i2s_tx_data(struct udevice *dev, void *data, uint data_size); + /* * Sends the given data through i2s tx * * @param pi2s_tx pointer of i2s transmitter parameter structure. * @param data address of the data buffer - * @param data_size array size of the int buffer (total size / size of int) - * + * @param data_size size of the data (in bytes) * @return int value 0 for success, -1 in case of error */ -int i2s_transfer_tx_data(struct i2s_uc_priv *pi2s_tx, unsigned int *data, - unsigned long data_size); +int i2s_transfer_tx_data(struct i2s_uc_priv *pi2s_tx, void *data, + uint data_size); /* * Initialise i2s transmiter diff --git a/test/dm/Makefile b/test/dm/Makefile index ef450b7ed81..28ede9a6695 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_FIRMWARE) += firmware.o obj-$(CONFIG_DM_GPIO) += gpio.o obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock.o obj-$(CONFIG_DM_I2C) += i2c.o +obj-$(CONFIG_DM_SOUND) += i2s.o obj-$(CONFIG_LED) += led.o obj-$(CONFIG_DM_MAILBOX) += mailbox.o obj-$(CONFIG_DM_MMC) += mmc.o diff --git a/test/dm/i2s.c b/test/dm/i2s.c new file mode 100644 index 00000000000..49ebc3523c0 --- /dev/null +++ b/test/dm/i2s.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include +#include + +/* Basic test of the i2s codec uclass */ +static int dm_test_i2s(struct unit_test_state *uts) +{ + struct udevice *dev; + u8 data[3]; + + /* check probe success */ + ut_assertok(uclass_first_device_err(UCLASS_I2S, &dev)); + data[0] = 1; + data[1] = 4; + data[2] = 6; + ut_assertok(i2s_tx_data(dev, data, ARRAY_SIZE(data))); + ut_asserteq(11, sandbox_get_i2s_sum(dev)); + ut_assertok(i2s_tx_data(dev, data, 1)); + ut_asserteq(12, sandbox_get_i2s_sum(dev)); + + return 0; +} +DM_TEST(dm_test_i2s, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); -- cgit v1.3.1 From d4901898654b664c41d8a03afc0e0fbf531b5812 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 10 Dec 2018 10:37:36 -0700 Subject: dm: sound: Create a uclass for sound The sound driver pulls together the audio codec and i2s drivers in order to actually make sounds. It supports setup() and play() methods. The sound_find_codec_i2s() function allows locating the linked codec and i2s devices. They can be referred to from uclass-private data. Add a uclass and a test for sound. Signed-off-by: Simon Glass --- arch/sandbox/dts/test.dts | 11 ++++ arch/sandbox/include/asm/test.h | 20 +++++++ cmd/sound.c | 23 +++++++- drivers/sound/Makefile | 1 + drivers/sound/sandbox.c | 67 +++++++++++++++++++++ drivers/sound/sound-uclass.c | 127 ++++++++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/sound.h | 70 +++++++++++++++++++++- test/dm/Makefile | 1 + test/dm/sound.c | 34 +++++++++++ 10 files changed, 351 insertions(+), 4 deletions(-) create mode 100644 drivers/sound/sound-uclass.c create mode 100644 test/dm/sound.c (limited to 'include') diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 5c2910c583b..82bd91936a6 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -538,6 +538,17 @@ compatible = "sandbox,smem"; }; + sound { + compatible = "sandbox,sound"; + cpu { + sound-dai = <&i2s 0>; + }; + + codec { + sound-dai = <&audio 0>; + }; + }; + spi@0 { #address-cells = <1>; #size-cells = <0>; diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index 71bd50bd5bc..74f96188220 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -141,4 +141,24 @@ void sandbox_get_codec_params(struct udevice *dev, int *interfacep, int *ratep, */ int sandbox_get_i2s_sum(struct udevice *dev); +/** + * sandbox_get_setup_called() - Returns the number of times setup(*) was called + * + * This is used in the sound test + * + * @dev: Device to check + * @return call count for the setup() method + */ +int sandbox_get_setup_called(struct udevice *dev); + +/** + * sandbox_get_sound_sum() - Read back the sum of the sound data so far + * + * This data is provided to the sandbox driver by the sound play() method. + * + * @dev: Device to check + * @return sum of audio data + */ +int sandbox_get_sound_sum(struct udevice *dev); + #endif diff --git a/cmd/sound.c b/cmd/sound.c index d1cbc14f8df..77f51529259 100644 --- a/cmd/sound.c +++ b/cmd/sound.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -14,11 +15,20 @@ DECLARE_GLOBAL_DATA_PTR; /* Initilaise sound subsystem */ static int do_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { +#ifdef CONFIG_DM_SOUND + struct udevice *dev; +#endif int ret; +#ifdef CONFIG_DM_SOUND + ret = uclass_first_device_err(UCLASS_SOUND, &dev); + if (!ret) + ret = sound_setup(dev); +#else ret = sound_init(gd->fdt_blob); +#endif if (ret) { - printf("Initialise Audio driver failed\n"); + printf("Initialise Audio driver failed (ret=%d)\n", ret); return CMD_RET_FAILURE; } @@ -28,6 +38,9 @@ static int do_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) /* play sound from buffer */ static int do_play(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { +#ifdef CONFIG_DM_SOUND + struct udevice *dev; +#endif int ret = 0; int msec = 1000; int freq = 400; @@ -37,9 +50,15 @@ static int do_play(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) if (argc > 2) freq = simple_strtoul(argv[2], NULL, 10); +#ifdef CONFIG_DM_SOUND + ret = uclass_first_device_err(UCLASS_SOUND, &dev); + if (!ret) + ret = sound_beep(dev, msec, freq); +#else ret = sound_play(msec, freq); +#endif if (ret) { - printf("play failed"); + printf("Sound device failed to play (err=%d)\n", ret); return CMD_RET_FAILURE; } diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index 4aced9d22b9..70d32c6d6f6 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_SOUND) += sound.o obj-$(CONFIG_DM_SOUND) += codec-uclass.o obj-$(CONFIG_DM_SOUND) += i2s-uclass.o obj-$(CONFIG_I2S) += sound-i2s.o +obj-$(CONFIG_DM_SOUND) += sound-uclass.o obj-$(CONFIG_I2S_SAMSUNG) += samsung-i2s.o obj-$(CONFIG_SOUND_SANDBOX) += sandbox.o obj-$(CONFIG_SOUND_WM8994) += wm8994.o diff --git a/drivers/sound/sandbox.c b/drivers/sound/sandbox.c index 2f7c68be0c8..ee2635f41d2 100644 --- a/drivers/sound/sandbox.c +++ b/drivers/sound/sandbox.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -22,6 +23,12 @@ struct sandbox_i2s_priv { int sum; /* Use to sum the provided audio data */ }; +struct sandbox_sound_priv { + int setup_called; + int sum; /* Use to sum the provided audio data */ +}; + +#ifndef CONFIG_DM_SOUND int sound_play(uint32_t msec, uint32_t frequency) { sandbox_sdl_sound_start(frequency); @@ -30,6 +37,7 @@ int sound_play(uint32_t msec, uint32_t frequency) return 0; } +#endif /* CONFIG_DM_SOUND */ int sound_init(const void *blob) { @@ -56,6 +64,20 @@ int sandbox_get_i2s_sum(struct udevice *dev) return priv->sum; } +int sandbox_get_setup_called(struct udevice *dev) +{ + struct sandbox_sound_priv *priv = dev_get_priv(dev); + + return priv->setup_called; +} + +int sandbox_get_sound_sum(struct udevice *dev) +{ + struct sandbox_sound_priv *priv = dev_get_priv(dev); + + return priv->sum; +} + static int sandbox_codec_set_params(struct udevice *dev, int interface, int rate, int mclk_freq, int bits_per_sample, uint channels) @@ -96,9 +118,35 @@ static int sandbox_i2s_probe(struct udevice *dev) uc_priv->channels = 2; uc_priv->id = 1; + return sandbox_sdl_sound_init(); +} + +static int sandbox_sound_setup(struct udevice *dev) +{ + struct sandbox_sound_priv *priv = dev_get_priv(dev); + + priv->setup_called++; + return 0; } +static int sandbox_sound_play(struct udevice *dev, void *data, uint data_size) +{ + struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev); + struct sandbox_sound_priv *priv = dev_get_priv(dev); + int i; + + for (i = 0; i < data_size; i++) + priv->sum += ((uint8_t *)data)[i]; + + return i2s_tx_data(uc_priv->i2s, data, data_size); +} + +static int sandbox_sound_probe(struct udevice *dev) +{ + return sound_find_codec_i2s(dev); +} + static const struct audio_codec_ops sandbox_codec_ops = { .set_params = sandbox_codec_set_params, }; @@ -133,3 +181,22 @@ U_BOOT_DRIVER(sandbox_i2s) = { .probe = sandbox_i2s_probe, .priv_auto_alloc_size = sizeof(struct sandbox_i2s_priv), }; + +static const struct sound_ops sandbox_sound_ops = { + .setup = sandbox_sound_setup, + .play = sandbox_sound_play, +}; + +static const struct udevice_id sandbox_sound_ids[] = { + { .compatible = "sandbox,sound" }, + { } +}; + +U_BOOT_DRIVER(sandbox_sound) = { + .name = "sandbox_sound", + .id = UCLASS_SOUND, + .of_match = sandbox_sound_ids, + .ops = &sandbox_sound_ops, + .priv_auto_alloc_size = sizeof(struct sandbox_sound_priv), + .probe = sandbox_sound_probe, +}; diff --git a/drivers/sound/sound-uclass.c b/drivers/sound/sound-uclass.c new file mode 100644 index 00000000000..71e753cb993 --- /dev/null +++ b/drivers/sound/sound-uclass.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include + +#define SOUND_BITS_IN_BYTE 8 + +int sound_setup(struct udevice *dev) +{ + struct sound_ops *ops = sound_get_ops(dev); + + if (!ops->setup) + return -ENOSYS; + + return ops->setup(dev); +} + +int sound_play(struct udevice *dev, void *data, uint data_size) +{ + struct sound_ops *ops = sound_get_ops(dev); + + if (!ops->play) + return -ENOSYS; + + return ops->play(dev, data, data_size); +} + +int sound_beep(struct udevice *dev, int msecs, int frequency_hz) +{ + struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev); + struct i2s_uc_priv *i2s_uc_priv = dev_get_uclass_priv(uc_priv->i2s); + unsigned short *data; + uint data_size; + int ret; + + ret = sound_setup(dev); + if (ret && ret != -EALREADY) + return ret; + + /* Buffer length computation */ + data_size = i2s_uc_priv->samplingrate * i2s_uc_priv->channels; + data_size *= (i2s_uc_priv->bitspersample / SOUND_BITS_IN_BYTE); + data = malloc(data_size); + if (!data) { + debug("%s: malloc failed\n", __func__); + return -ENOMEM; + } + + sound_create_square_wave(i2s_uc_priv->samplingrate, data, data_size, + frequency_hz); + + while (msecs >= 1000) { + ret = sound_play(dev, data, data_size); + msecs -= 1000; + } + if (msecs) { + unsigned long size = + (data_size * msecs) / (sizeof(int) * 1000); + + ret = sound_play(dev, data, size); + } + + free(data); + + return ret; +} + +int sound_find_codec_i2s(struct udevice *dev) +{ + struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev); + struct ofnode_phandle_args args; + ofnode node; + int ret; + + /* First the codec */ + node = ofnode_find_subnode(dev_ofnode(dev), "codec"); + if (!ofnode_valid(node)) { + debug("Failed to find /cpu subnode\n"); + return -EINVAL; + } + ret = ofnode_parse_phandle_with_args(node, "sound-dai", + "#sound-dai-cells", 0, 0, &args); + if (ret) { + debug("Cannot find phandle: %d\n", ret); + return ret; + } + ret = uclass_get_device_by_ofnode(UCLASS_AUDIO_CODEC, args.node, + &uc_priv->codec); + if (ret) { + debug("Cannot find codec: %d\n", ret); + return ret; + } + + /* Now the i2s */ + node = ofnode_find_subnode(dev_ofnode(dev), "cpu"); + if (!ofnode_valid(node)) { + debug("Failed to find /cpu subnode\n"); + return -EINVAL; + } + ret = ofnode_parse_phandle_with_args(node, "sound-dai", + "#sound-dai-cells", 0, 0, &args); + if (ret) { + debug("Cannot find phandle: %d\n", ret); + return ret; + } + ret = uclass_get_device_by_ofnode(UCLASS_I2S, args.node, &uc_priv->i2s); + if (ret) { + debug("Cannot find i2s: %d\n", ret); + return ret; + } + debug("Probed sound '%s' with codec '%s' and i2s '%s'\n", dev->name, + uc_priv->codec->name, uc_priv->i2s->name); + + return 0; +} + +UCLASS_DRIVER(sound) = { + .id = UCLASS_SOUND, + .name = "sound", + .per_device_auto_alloc_size = sizeof(struct sound_uc_priv), +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 1dffb669329..f3bafb3c635 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -84,6 +84,7 @@ enum uclass_id { UCLASS_SERIAL, /* Serial UART */ UCLASS_SIMPLE_BUS, /* Bus with child devices */ UCLASS_SMEM, /* Shared memory interface */ + UCLASS_SOUND, /* Playing simple sounds */ UCLASS_SPI, /* SPI bus */ UCLASS_SPI_FLASH, /* SPI flash */ UCLASS_SPI_GENERIC, /* Generic SPI flash target */ diff --git a/include/sound.h b/include/sound.h index c4ac3193fe7..c94d2c37265 100644 --- a/include/sound.h +++ b/include/sound.h @@ -19,12 +19,27 @@ struct sound_codec_info { int i2c_dev_addr; }; -/* +/** + * struct sound_uc_priv - private uclass information about each sound device + * + * This is used to line the codec and i2s together + * + * @codec: Codec that is used for this sound device + * @i2s: I2S bus that is used for this sound device + * @setup_done: true if setup() has been called + */ +struct sound_uc_priv { + struct udevice *codec; + struct udevice *i2s; + int setup_done; +}; + +/** * Generates square wave sound data for 1 second * * @param sample_rate Sample rate in Hz * @param data data buffer pointer - * @param size size of the buffer + * @param size size of the buffer in bytes * @param freq frequency of the wave */ void sound_create_square_wave(uint sample_rate, unsigned short *data, int size, @@ -37,6 +52,56 @@ void sound_create_square_wave(uint sample_rate, unsigned short *data, int size, */ int sound_init(const void *blob); +#ifdef CONFIG_DM_SOUND +/* + * The sound uclass brings together a data transport (currently only I2C) and a + * codec (currently connected over I2C). + */ + +/* Operations for sound */ +struct sound_ops { + /** + * setup() - Set up to play a sound + */ + int (*setup)(struct udevice *dev); + + /** + * play() - Play a beep + * + * @dev: Sound device + * @data: Data buffer to play + * @data_size: Size of data buffer in bytes + * @return 0 if OK, -ve on error + */ + int (*play)(struct udevice *dev, void *data, uint data_size); +}; + +#define sound_get_ops(dev) ((struct sound_ops *)(dev)->driver->ops) + +/** + * setup() - Set up to play a sound + */ +int sound_setup(struct udevice *dev); + +/** + * play() - Play a beep + * + * @dev: Sound device + * @msecs: Duration of beep in milliseconds + * @frequency_hz: Frequency of the beep in Hertz + * @return 0 if OK, -ve on error + */ +int sound_beep(struct udevice *dev, int msecs, int frequency_hz); + +/** + * sound_find_codec_i2s() - Called by sound drivers to locate codec and i2s + * + * This finds the audio codec and i2s devices and puts them in the uclass's + * private data for this device. + */ +int sound_find_codec_i2s(struct udevice *dev); + +#else /* * plays the pcm data buffer in pcm_data.h through i2s1 to make the * sine wave sound @@ -44,5 +109,6 @@ int sound_init(const void *blob); * @return int 0 for success, -1 for error */ int sound_play(uint32_t msec, uint32_t frequency); +#endif /* CONFIG_DM_SOUND */ #endif /* __SOUND__H__ */ diff --git a/test/dm/Makefile b/test/dm/Makefile index 28ede9a6695..73f5dcf739e 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_AXI) += axi.o obj-$(CONFIG_MISC) += misc.o obj-$(CONFIG_DM_SERIAL) += serial.o obj-$(CONFIG_CPU) += cpu.o +obj-$(CONFIG_DM_SOUND) += sound.o obj-$(CONFIG_TEE) += tee.o obj-$(CONFIG_VIRTIO_SANDBOX) += virtio.o obj-$(CONFIG_DMA) += dma.o diff --git a/test/dm/sound.c b/test/dm/sound.c new file mode 100644 index 00000000000..7d0b36e7a56 --- /dev/null +++ b/test/dm/sound.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include +#include + +/* Basic test of the sound codec uclass */ +static int dm_test_sound(struct unit_test_state *uts) +{ + struct sound_uc_priv *uc_priv; + struct udevice *dev; + + /* check probe success */ + ut_assertok(uclass_first_device_err(UCLASS_SOUND, &dev)); + uc_priv = dev_get_uclass_priv(dev); + ut_asserteq_str("audio-codec", uc_priv->codec->name); + ut_asserteq_str("i2s", uc_priv->i2s->name); + ut_asserteq(0, sandbox_get_setup_called(dev)); + + ut_assertok(sound_beep(dev, 1, 100)); + ut_asserteq(4560, sandbox_get_sound_sum(dev)); + ut_assertok(sound_beep(dev, 1, 100)); + ut_asserteq(9120, sandbox_get_sound_sum(dev)); + + return 0; +} +DM_TEST(dm_test_sound, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); -- cgit v1.3.1 From a1b17e4f4c820c5ffe77ffa0c716e8b3b5d69866 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 10 Dec 2018 10:37:37 -0700 Subject: dm: core: Add a function to read into a unsigned int The current dev_read...() functions use s32 and u32 which are convenient for device tree but not so useful for normal code, which often wants to use normal integers for values. Add a helper which supports returning an unsigned int. Also add signed versions of the unsigned readers. Signed-off-by: Simon Glass --- arch/sandbox/dts/test.dts | 2 ++ drivers/core/read.c | 23 +++++++++++++++++++ include/dm/read.h | 58 +++++++++++++++++++++++++++++++++++++++++++++++ test/dm/test-fdt.c | 35 ++++++++++++++++++++++++++++ 4 files changed, 118 insertions(+) (limited to 'include') diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 82bd91936a6..3790b4c5208 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -87,6 +87,8 @@ test2-gpios = <&gpio_a 1>, <&gpio_a 4>, <&gpio_b 6 1 3 2 1>, <&gpio_b 7 2 3 2 1>, <&gpio_b 8 4 3 2 1>, <&gpio_b 9 0xc 3 2 1>; + int-value = <1234>; + uint-value = <(-1234)>; }; junk { diff --git a/drivers/core/read.c b/drivers/core/read.c index cdd78be03e2..3c46b3674ed 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -21,6 +21,29 @@ int dev_read_u32_default(struct udevice *dev, const char *propname, int def) return ofnode_read_u32_default(dev_ofnode(dev), propname, def); } +int dev_read_s32(struct udevice *dev, const char *propname, s32 *outp) +{ + return ofnode_read_u32(dev_ofnode(dev), propname, (u32 *)outp); +} + +int dev_read_s32_default(struct udevice *dev, const char *propname, int def) +{ + return ofnode_read_u32_default(dev_ofnode(dev), propname, def); +} + +int dev_read_u32u(struct udevice *dev, const char *propname, uint *outp) +{ + u32 val; + int ret; + + ret = ofnode_read_u32(dev_ofnode(dev), propname, &val); + if (ret) + return ret; + *outp = val; + + return 0; +} + const char *dev_read_string(struct udevice *dev, const char *propname) { return ofnode_read_string(dev_ofnode(dev), propname); diff --git a/include/dm/read.h b/include/dm/read.h index efcbee15eca..389e30e7fb4 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -64,6 +64,38 @@ int dev_read_u32(struct udevice *dev, const char *propname, u32 *outp); */ int dev_read_u32_default(struct udevice *dev, const char *propname, int def); +/** + * dev_read_s32() - read a signed 32-bit integer from a device's DT property + * + * @dev: device to read DT property from + * @propname: name of the property to read from + * @outp: place to put value (if found) + * @return 0 if OK, -ve on error + */ +int dev_read_s32(struct udevice *dev, const char *propname, s32 *outp); + +/** + * dev_read_s32_default() - read a signed 32-bit int from a device's DT property + * + * @dev: device to read DT property from + * @propname: name of the property to read from + * @def: default value to return if the property has no value + * @return property value, or @def if not found + */ +int dev_read_s32_default(struct udevice *dev, const char *propname, int def); + +/** + * dev_read_u32u() - read a 32-bit integer from a device's DT property + * + * This version uses a standard uint type. + * + * @dev: device to read DT property from + * @propname: name of the property to read from + * @outp: place to put value (if found) + * @return 0 if OK, -ve on error + */ +int dev_read_u32u(struct udevice *dev, const char *propname, uint *outp); + /** * dev_read_string() - Read a string from a device's DT property * @@ -492,6 +524,32 @@ static inline int dev_read_u32_default(struct udevice *dev, return ofnode_read_u32_default(dev_ofnode(dev), propname, def); } +static inline int dev_read_s32(struct udevice *dev, + const char *propname, s32 *outp) +{ + return ofnode_read_s32(dev_ofnode(dev), propname, outp); +} + +static inline int dev_read_s32_default(struct udevice *dev, + const char *propname, int def) +{ + return ofnode_read_s32_default(dev_ofnode(dev), propname, def); +} + +static inline int dev_read_u32u(struct udevice *dev, + const char *propname, uint *outp) +{ + u32 val; + int ret; + + ret = ofnode_read_u32(dev_ofnode(dev), propname, &val); + if (ret) + return ret; + *outp = val; + + return 0; +} + static inline const char *dev_read_string(struct udevice *dev, const char *propname) { diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c index 96d2528accb..984b80c02c8 100644 --- a/test/dm/test-fdt.c +++ b/test/dm/test-fdt.c @@ -736,3 +736,38 @@ static int dm_test_first_child(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_first_child, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test integer functions in dm_read_...() */ +static int dm_test_read_int(struct unit_test_state *uts) +{ + struct udevice *dev; + u32 val32; + s32 sval; + uint val; + + ut_assertok(uclass_first_device_err(UCLASS_TEST_FDT, &dev)); + ut_asserteq_str("a-test", dev->name); + ut_assertok(dev_read_u32(dev, "int-value", &val32)); + ut_asserteq(1234, val32); + + ut_asserteq(-EINVAL, dev_read_u32(dev, "missing", &val32)); + ut_asserteq(6, dev_read_u32_default(dev, "missing", 6)); + + ut_asserteq(1234, dev_read_u32_default(dev, "int-value", 6)); + ut_asserteq(1234, val32); + + ut_asserteq(-EINVAL, dev_read_s32(dev, "missing", &sval)); + ut_asserteq(6, dev_read_s32_default(dev, "missing", 6)); + + ut_asserteq(-1234, dev_read_s32_default(dev, "uint-value", 6)); + ut_assertok(dev_read_s32(dev, "uint-value", &sval)); + ut_asserteq(-1234, sval); + + val = 0; + ut_asserteq(-EINVAL, dev_read_u32u(dev, "missing", &val)); + ut_assertok(dev_read_u32u(dev, "uint-value", &val)); + ut_asserteq(-1234, val); + + return 0; +} +DM_TEST(dm_test_read_int, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); -- cgit v1.3.1 From f2b25c9bf8212139f43ded090c78d604babc4337 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 10 Dec 2018 10:37:47 -0700 Subject: dm: sound: Complete migration to driver model All users of sound are converted to use driver model. Drop the old code and the CONFIG_DM_SOUND option. Signed-off-by: Simon Glass --- arch/sandbox/cpu/sdl.c | 1 - arch/sandbox/include/asm/sdl.h | 21 ++-- arch/sandbox/include/asm/sound.h | 13 --- cmd/sound.c | 12 --- configs/arndale_defconfig | 1 - configs/peach-pi_defconfig | 1 - configs/peach-pit_defconfig | 1 - configs/smdk5250_defconfig | 1 - configs/snow_defconfig | 1 - configs/spring_defconfig | 1 - drivers/sound/Kconfig | 6 -- drivers/sound/Makefile | 10 +- drivers/sound/max98095.c | 78 --------------- drivers/sound/sandbox.c | 19 +--- drivers/sound/sound-i2s.c | 206 --------------------------------------- drivers/sound/wm8994.c | 95 ------------------ include/sound.h | 18 ---- test/dm/Makefile | 6 +- 18 files changed, 16 insertions(+), 475 deletions(-) delete mode 100644 arch/sandbox/include/asm/sound.h delete mode 100644 drivers/sound/sound-i2s.c (limited to 'include') diff --git a/arch/sandbox/cpu/sdl.c b/arch/sandbox/cpu/sdl.c index 32fa1fffc9b..47b706513e4 100644 --- a/arch/sandbox/cpu/sdl.c +++ b/arch/sandbox/cpu/sdl.c @@ -7,7 +7,6 @@ #include #include #include -#include #include enum { diff --git a/arch/sandbox/include/asm/sdl.h b/arch/sandbox/include/asm/sdl.h index 0143ed9e621..2799a8bee06 100644 --- a/arch/sandbox/include/asm/sdl.h +++ b/arch/sandbox/include/asm/sdl.h @@ -54,12 +54,12 @@ int sandbox_sdl_scan_keys(int key[], int max_keys); int sandbox_sdl_key_pressed(int keycode); /** - * sandbox_sdl_sound_start() - start playing a sound + * sandbox_sdl_sound_play() - Play a sound * - * @frequency: Frequency of sounds in Hertz - * @return 0 if OK, -ENODEV if no sound is available + * @data: Data to play (typically 16-bit) + * @count: Number of bytes in data */ -int sandbox_sdl_sound_start(uint frequency); +int sandbox_sdl_sound_play(const void *data, uint count); /** * sandbox_sdl_sound_stop() - stop playing a sound @@ -68,14 +68,6 @@ int sandbox_sdl_sound_start(uint frequency); */ int sandbox_sdl_sound_stop(void); -/** - * sandbox_sdl_sound_play() - Play a sound - * - * @data: Data to play (typically 16-bit) - * @count: Number of bytes in data - */ -int sandbox_sdl_sound_play(const void *data, uint count); - /** * sandbox_sdl_sound_init() - set up the sound system * @@ -110,6 +102,11 @@ static inline int sandbox_sdl_sound_start(uint frequency) return -ENODEV; } +int sandbox_sdl_sound_play(const void *data, uint count) +{ + return -ENODEV; +} + static inline int sandbox_sdl_sound_stop(void) { return -ENODEV; diff --git a/arch/sandbox/include/asm/sound.h b/arch/sandbox/include/asm/sound.h deleted file mode 100644 index a6015b0f60f..00000000000 --- a/arch/sandbox/include/asm/sound.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 2013 Google, Inc - */ - -#ifndef __SANDBOX_SOUND_H -#define __SANDBOX_SOUND_H - -int sound_play(unsigned int msec, unsigned int frequency); - -int sound_init(const void *blob); - -#endif diff --git a/cmd/sound.c b/cmd/sound.c index 77f51529259..638f29df21d 100644 --- a/cmd/sound.c +++ b/cmd/sound.c @@ -15,18 +15,12 @@ DECLARE_GLOBAL_DATA_PTR; /* Initilaise sound subsystem */ static int do_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { -#ifdef CONFIG_DM_SOUND struct udevice *dev; -#endif int ret; -#ifdef CONFIG_DM_SOUND ret = uclass_first_device_err(UCLASS_SOUND, &dev); if (!ret) ret = sound_setup(dev); -#else - ret = sound_init(gd->fdt_blob); -#endif if (ret) { printf("Initialise Audio driver failed (ret=%d)\n", ret); return CMD_RET_FAILURE; @@ -38,9 +32,7 @@ static int do_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) /* play sound from buffer */ static int do_play(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { -#ifdef CONFIG_DM_SOUND struct udevice *dev; -#endif int ret = 0; int msec = 1000; int freq = 400; @@ -50,13 +42,9 @@ static int do_play(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) if (argc > 2) freq = simple_strtoul(argv[2], NULL, 10); -#ifdef CONFIG_DM_SOUND ret = uclass_first_device_err(UCLASS_SOUND, &dev); if (!ret) ret = sound_beep(dev, msec, freq); -#else - ret = sound_play(msec, freq); -#endif if (ret) { printf("Sound device failed to play (err=%d)\n", ret); return CMD_RET_FAILURE; diff --git a/configs/arndale_defconfig b/configs/arndale_defconfig index 22881c3a2c6..2b6af4b2215 100644 --- a/configs/arndale_defconfig +++ b/configs/arndale_defconfig @@ -31,7 +31,6 @@ CONFIG_MMC_SDHCI_S5P=y CONFIG_SMC911X=y CONFIG_SMC911X_BASE=0x5000000 CONFIG_SOUND=y -CONFIG_DM_SOUND=y CONFIG_I2S=y CONFIG_I2S_SAMSUNG=y CONFIG_SOUND_MAX98095=y diff --git a/configs/peach-pi_defconfig b/configs/peach-pi_defconfig index 32b32dd901c..14c835cad81 100644 --- a/configs/peach-pi_defconfig +++ b/configs/peach-pi_defconfig @@ -50,7 +50,6 @@ CONFIG_REGULATOR_TPS65090=y CONFIG_DM_PWM=y CONFIG_PWM_EXYNOS=y CONFIG_SOUND=y -CONFIG_DM_SOUND=y CONFIG_I2S=y CONFIG_I2S_SAMSUNG=y CONFIG_SOUND_MAX98090=y diff --git a/configs/peach-pit_defconfig b/configs/peach-pit_defconfig index 7018737ab4f..9a3a11504de 100644 --- a/configs/peach-pit_defconfig +++ b/configs/peach-pit_defconfig @@ -49,7 +49,6 @@ CONFIG_REGULATOR_TPS65090=y CONFIG_DM_PWM=y CONFIG_PWM_EXYNOS=y CONFIG_SOUND=y -CONFIG_DM_SOUND=y CONFIG_I2S=y CONFIG_I2S_SAMSUNG=y CONFIG_SOUND_MAX98090=y diff --git a/configs/smdk5250_defconfig b/configs/smdk5250_defconfig index 1e058227e41..21018d8b1b1 100644 --- a/configs/smdk5250_defconfig +++ b/configs/smdk5250_defconfig @@ -43,7 +43,6 @@ CONFIG_DM_PMIC_MAX77686=y CONFIG_DM_REGULATOR=y CONFIG_DM_REGULATOR_MAX77686=y CONFIG_SOUND=y -CONFIG_DM_SOUND=y CONFIG_I2S=y CONFIG_I2S_SAMSUNG=y CONFIG_SOUND_MAX98095=y diff --git a/configs/snow_defconfig b/configs/snow_defconfig index 10e11fbb337..e0c1bf862c0 100644 --- a/configs/snow_defconfig +++ b/configs/snow_defconfig @@ -60,7 +60,6 @@ CONFIG_DM_PWM=y CONFIG_PWM_EXYNOS=y CONFIG_DEBUG_UART_S5P=y CONFIG_SOUND=y -CONFIG_DM_SOUND=y CONFIG_I2S=y CONFIG_I2S_SAMSUNG=y CONFIG_SOUND_MAX98095=y diff --git a/configs/spring_defconfig b/configs/spring_defconfig index 844a87734b8..c089517692e 100644 --- a/configs/spring_defconfig +++ b/configs/spring_defconfig @@ -60,7 +60,6 @@ CONFIG_DM_PWM=y CONFIG_PWM_EXYNOS=y CONFIG_DEBUG_UART_S5P=y CONFIG_SOUND=y -CONFIG_DM_SOUND=y CONFIG_I2S=y CONFIG_I2S_SAMSUNG=y CONFIG_SOUND_MAX98095=y diff --git a/drivers/sound/Kconfig b/drivers/sound/Kconfig index 18d7ca1dcb3..c0d97cca338 100644 --- a/drivers/sound/Kconfig +++ b/drivers/sound/Kconfig @@ -12,12 +12,6 @@ config SOUND audio codecs are called from the sound-i2s code. This could be converted to driver model. -config DM_SOUND - bool "Use driver model for sound" - help - Enable this option to use driver model for sound devices. This is a - migration option and will be removed. - config I2S bool "Enable I2S support" depends on SOUND diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index 937df152fe6..1de4346ec7a 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -4,16 +4,12 @@ # R. Chandrasekar obj-$(CONFIG_SOUND) += sound.o -obj-$(CONFIG_DM_SOUND) += codec-uclass.o -obj-$(CONFIG_DM_SOUND) += i2s-uclass.o -obj-$(CONFIG_DM_SOUND) += sound-uclass.o +obj-$(CONFIG_SOUND) += codec-uclass.o +obj-$(CONFIG_SOUND) += i2s-uclass.o +obj-$(CONFIG_SOUND) += sound-uclass.o obj-$(CONFIG_I2S_SAMSUNG) += samsung-i2s.o obj-$(CONFIG_SOUND_SANDBOX) += sandbox.o -ifdef CONFIG_DM_SOUND obj-$(CONFIG_I2S_SAMSUNG) += samsung_sound.o -else -obj-$(CONFIG_I2S) += sound-i2s.o -endif obj-$(CONFIG_SOUND_WM8994) += wm8994.o obj-$(CONFIG_SOUND_MAX98090) += max98090.o maxim_codec.o obj-$(CONFIG_SOUND_MAX98095) += max98095.o maxim_codec.o diff --git a/drivers/sound/max98095.c b/drivers/sound/max98095.c index e9bf64f82f8..93be50c34a2 100644 --- a/drivers/sound/max98095.c +++ b/drivers/sound/max98095.c @@ -432,84 +432,6 @@ static int max98095_do_init(struct maxim_priv *priv, return ret; } -#ifndef CONFIG_DM_SOUND -static int get_max98095_codec_values(struct sound_codec_info *pcodec_info, - const void *blob) -{ - int error = 0; - enum fdt_compat_id compat; - int node; - int parent; - - /* Get the node from FDT for codec */ - node = fdtdec_next_compatible(blob, 0, COMPAT_MAXIM_98095_CODEC); - if (node <= 0) { - debug("EXYNOS_SOUND: No node for codec in device tree\n"); - debug("node = %d\n", node); - return -1; - } - - parent = fdt_parent_offset(blob, node); - if (parent < 0) { - debug("%s: Cannot find node parent\n", __func__); - return -1; - } - - compat = fdtdec_lookup(blob, parent); - switch (compat) { - case COMPAT_SAMSUNG_S3C2440_I2C: - pcodec_info->i2c_bus = i2c_get_bus_num_fdt(parent); - error |= pcodec_info->i2c_bus; - debug("i2c bus = %d\n", pcodec_info->i2c_bus); - pcodec_info->i2c_dev_addr = fdtdec_get_int(blob, node, - "reg", 0); - error |= pcodec_info->i2c_dev_addr; - debug("i2c dev addr = %x\n", pcodec_info->i2c_dev_addr); - break; - default: - debug("%s: Unknown compat id %d\n", __func__, compat); - return -1; - } - if (error == -1) { - debug("fail to get max98095 codec node properties\n"); - return -1; - } - - return 0; -} - -/* max98095 Device Initialisation */ -int max98095_init(const void *blob, enum en_max_audio_interface aif_id, - int sampling_rate, int mclk_freq, - int bits_per_sample) -{ - int ret; - int old_bus = i2c_get_bus_num(); - struct sound_codec_info pcodec_info; - struct max98095_priv max98095_info; - - if (get_max98095_codec_values(&pcodec_info, blob) < 0) { - debug("FDT Codec values failed\n"); - return -1; - } - - i2c_set_bus_num(pcodec_info.i2c_bus); - - max98095_info.i2c_addr = pcodec_info.i2c_dev_addr; - ret = max98095_device_init(&max98095_info); - if (ret < 0) { - debug("%s: max98095 codec chip init failed\n", __func__); - return ret; - } - - ret = max98095_do_init(&max98095_info, aif_id, sampling_rate, mclk_freq, - bits_per_sample); - i2c_set_bus_num(old_bus); - - return ret; -} -#endif - static int max98095_set_params(struct udevice *dev, int interface, int rate, int mclk_freq, int bits_per_sample, uint channels) diff --git a/drivers/sound/sandbox.c b/drivers/sound/sandbox.c index 83b3295f0d4..089d8309727 100644 --- a/drivers/sound/sandbox.c +++ b/drivers/sound/sandbox.c @@ -8,7 +8,6 @@ #include #include #include -#include #include struct sandbox_codec_priv { @@ -28,22 +27,6 @@ struct sandbox_sound_priv { int sum; /* Use to sum the provided audio data */ }; -#ifndef CONFIG_DM_SOUND -int sound_play(uint32_t msec, uint32_t frequency) -{ - sandbox_sdl_sound_start(frequency); - mdelay(msec); - sandbox_sdl_sound_stop(); - - return 0; -} -#endif /* CONFIG_DM_SOUND */ - -int sound_init(const void *blob) -{ - return sandbox_sdl_sound_init(); -} - void sandbox_get_codec_params(struct udevice *dev, int *interfacep, int *ratep, int *mclk_freqp, int *bits_per_samplep, uint *channelsp) @@ -102,7 +85,7 @@ static int sandbox_i2s_tx_data(struct udevice *dev, void *data, for (i = 0; i < data_size; i++) priv->sum += ((uint8_t *)data)[i]; - return 0; + return sandbox_sdl_sound_play(data, data_size); } static int sandbox_i2s_probe(struct udevice *dev) diff --git a/drivers/sound/sound-i2s.c b/drivers/sound/sound-i2s.c deleted file mode 100644 index a2fc78154f1..00000000000 --- a/drivers/sound/sound-i2s.c +++ /dev/null @@ -1,206 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2012 Samsung Electronics - * R. Chandrasekar - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "wm8994.h" -#include "max98095.h" - -/* defines */ -#define SOUND_400_HZ 400 -#define SOUND_BITS_IN_BYTE 8 - -static struct i2s_uc_priv g_i2stx_pri; - -/* - * get_sound_i2s_values gets values for i2s parameters - * - * @param i2s_uc_priv i2s transmitter transfer param structure - * @param blob FDT blob if enabled else NULL - */ -static int get_sound_i2s_values(struct i2s_uc_priv *i2s, const void *blob) -{ - int node; - int error = 0; - int base; - - node = fdt_path_offset(blob, "i2s"); - if (node <= 0) { - debug("EXYNOS_SOUND: No node for sound in device tree\n"); - return -1; - } - - /* - * Get the pre-defined sound specific values from FDT. - * All of these are expected to be correct otherwise - * wrong register values in i2s setup parameters - * may result in no sound play. - */ - base = fdtdec_get_addr(blob, node, "reg"); - if (base == FDT_ADDR_T_NONE) { - debug("%s: Missing i2s base\n", __func__); - return -1; - } - i2s->base_address = base; - - i2s->audio_pll_clk = fdtdec_get_int(blob, - node, "samsung,i2s-epll-clock-frequency", -1); - error |= i2s->audio_pll_clk; - debug("audio_pll_clk = %d\n", i2s->audio_pll_clk); - i2s->samplingrate = fdtdec_get_int(blob, - node, "samsung,i2s-sampling-rate", -1); - error |= i2s->samplingrate; - debug("samplingrate = %d\n", i2s->samplingrate); - i2s->bitspersample = fdtdec_get_int(blob, - node, "samsung,i2s-bits-per-sample", -1); - error |= i2s->bitspersample; - debug("bitspersample = %d\n", i2s->bitspersample); - i2s->channels = fdtdec_get_int(blob, - node, "samsung,i2s-channels", -1); - error |= i2s->channels; - debug("channels = %d\n", i2s->channels); - i2s->rfs = fdtdec_get_int(blob, - node, "samsung,i2s-lr-clk-framesize", -1); - error |= i2s->rfs; - debug("rfs = %d\n", i2s->rfs); - i2s->bfs = fdtdec_get_int(blob, - node, "samsung,i2s-bit-clk-framesize", -1); - error |= i2s->bfs; - debug("bfs = %d\n", i2s->bfs); - - i2s->id = fdtdec_get_int(blob, node, "samsung,i2s-id", -1); - error |= i2s->id; - debug("id = %d\n", i2s->id); - - if (error == -1) { - debug("fail to get sound i2s node properties\n"); - return -1; - } - - return 0; -} - -/* - * Init codec - * - * @param blob FDT blob - * @param pi2s_tx i2s parameters required by codec - * @return int value, 0 for success - */ -static int codec_init(const void *blob, struct i2s_uc_priv *pi2s_tx) -{ - int ret; - const char *codectype; - int node; - - /* Get the node from FDT for sound */ - node = fdt_path_offset(blob, "i2s"); - if (node <= 0) { - debug("EXYNOS_SOUND: No node for sound in device tree\n"); - debug("node = %d\n", node); - return -1; - } - - /* - * Get the pre-defined sound codec specific values from FDT. - * All of these are expected to be correct otherwise sound - * can not be played - */ - codectype = fdt_getprop(blob, node, "samsung,codec-type", NULL); - debug("device = %s\n", codectype); - if (!strcmp(codectype, "wm8994")) { - /* Check the codec type and initialise the same */ - ret = wm8994_init(blob, pi2s_tx->id, pi2s_tx->samplingrate, - (pi2s_tx->samplingrate * (pi2s_tx->rfs)), - pi2s_tx->bitspersample, pi2s_tx->channels); - } else if (!strcmp(codectype, "max98095")) { - ret = max98095_init(blob, pi2s_tx->id, pi2s_tx->samplingrate, - (pi2s_tx->samplingrate * (pi2s_tx->rfs)), - pi2s_tx->bitspersample); - } else { - debug("%s: Unknown codec type %s\n", __func__, codectype); - return -1; - } - - if (ret) { - debug("%s: Codec init failed\n", __func__); - return -1; - } - - return 0; -} - -int sound_init(const void *blob) -{ - int ret; - struct i2s_uc_priv *pi2s_tx = &g_i2stx_pri; - - /* Get the I2S Values */ - if (get_sound_i2s_values(pi2s_tx, blob) < 0) { - debug(" FDT I2S values failed\n"); - return -1; - } - - if (codec_init(blob, pi2s_tx) < 0) { - debug(" Codec init failed\n"); - return -1; - } - - ret = i2s_tx_init(pi2s_tx); - if (ret) { - debug("%s: Failed to init i2c transmit: ret=%d\n", __func__, - ret); - return ret; - } - - - return ret; -} - -int sound_play(uint32_t msec, uint32_t frequency) -{ - unsigned int *data; - unsigned long data_size; - unsigned int ret = 0; - - /*Buffer length computation */ - data_size = g_i2stx_pri.samplingrate * g_i2stx_pri.channels; - data_size *= (g_i2stx_pri.bitspersample / SOUND_BITS_IN_BYTE); - data = malloc(data_size); - - if (data == NULL) { - debug("%s: malloc failed\n", __func__); - return -1; - } - - sound_create_square_wave(g_i2stx_pri.samplingrate, - (unsigned short *)data, - data_size / sizeof(unsigned short), - frequency); - - while (msec >= 1000) { - ret = i2s_transfer_tx_data(&g_i2stx_pri, data, - (data_size / sizeof(int))); - msec -= 1000; - } - if (msec) { - unsigned long size = - (data_size * msec) / (sizeof(int) * 1000); - - ret = i2s_transfer_tx_data(&g_i2stx_pri, data, size); - } - - free(data); - - return ret; -} diff --git a/drivers/sound/wm8994.c b/drivers/sound/wm8994.c index d731a0dd863..b290c4e8791 100644 --- a/drivers/sound/wm8994.c +++ b/drivers/sound/wm8994.c @@ -40,7 +40,6 @@ struct wm8994_priv { int mclk[WM8994_MAX_AIF]; /* master clock frequency in Hz */ int aifclk[WM8994_MAX_AIF]; /* audio interface clock in Hz */ struct wm8994_fll_config fll[2]; /* fll config to configure fll */ - int i2c_addr; struct udevice *dev; }; @@ -82,12 +81,7 @@ static int wm8994_i2c_write(struct wm8994_priv *priv, unsigned int reg, val[1] = (unsigned char)(data & 0xff); debug("Write Addr : 0x%04X, Data : 0x%04X\n", reg, data); -#ifdef CONFIG_DM_SOUND - debug("dev = %s\n", priv->dev->name); return dm_i2c_write(priv->dev, reg, val, 2); -#else - return i2c_write(priv->i2c_addr, reg, 2, val, 2); -#endif } /* @@ -105,11 +99,7 @@ static unsigned int wm8994_i2c_read(struct wm8994_priv *priv, unsigned int reg, unsigned char val[2]; int ret; -#ifdef CONFIG_DM_SOUND ret = dm_i2c_read(priv->dev, reg, val, 1); -#else - ret = i2c_read(priv->i2c_addr, reg, 2, val, 2); -#endif if (ret != 0) { debug("%s: Error while reading register %#04x\n", __func__, reg); @@ -819,61 +809,6 @@ err: return -1; } -#ifndef CONFIG_DM_SOUND -/* - * Gets fdt values for wm8994 config parameters - * - * @param pcodec_info codec information structure - * @param blob FDT blob - * @return int value, 0 for success - */ -static int get_codec_values(struct sound_codec_info *pcodec_info, - const void *blob) -{ - int error = 0; - enum fdt_compat_id compat; - int node; - int parent; - - /* Get the node from FDT for codec */ - node = fdtdec_next_compatible(blob, 0, COMPAT_WOLFSON_WM8994_CODEC); - if (node <= 0) { - debug("EXYNOS_SOUND: No node for codec in device tree\n"); - debug("node = %d\n", node); - return -1; - } - - parent = fdt_parent_offset(blob, node); - if (parent < 0) { - debug("%s: Cannot find node parent\n", __func__); - return -1; - } - - compat = fdtdec_lookup(blob, parent); - switch (compat) { - case COMPAT_SAMSUNG_S3C2440_I2C: - pcodec_info->i2c_bus = i2c_get_bus_num_fdt(parent); - error |= pcodec_info->i2c_bus; - debug("i2c bus = %d\n", pcodec_info->i2c_bus); - pcodec_info->i2c_dev_addr = fdtdec_get_int(blob, node, - "reg", 0); - error |= pcodec_info->i2c_dev_addr; - debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr); - break; - default: - debug("%s: Unknown compat id %d\n", __func__, compat); - return -1; - } - - if (error == -1) { - debug("fail to get wm8994 codec node properties\n"); - return -1; - } - - return 0; -} -#endif - static int _wm8994_init(struct wm8994_priv *priv, enum en_audio_interface aif_id, int sampling_rate, int mclk_freq, int bits_per_sample, @@ -905,36 +840,6 @@ static int _wm8994_init(struct wm8994_priv *priv, return ret; } -#ifndef CONFIG_DM_SOUND -/* WM8994 Device Initialisation */ -int wm8994_init(const void *blob, enum en_audio_interface aif_id, - int sampling_rate, int mclk_freq, int bits_per_sample, - unsigned int channels) -{ - struct sound_codec_info pcodec_info; - struct wm8994_priv wm8994_info; - int ret; - - /* Get the codec Values */ - if (get_codec_values(&pcodec_info, blob) < 0) { - debug("FDT Codec values failed\n"); - return -1; - } - - /* shift the device address by 1 for 7 bit addressing */ - wm8994_info.i2c_addr = pcodec_info.i2c_dev_addr; - i2c_set_bus_num(pcodec_info.i2c_bus); - ret = wm8994_device_init(&wm8994_info); - if (ret < 0) { - debug("%s: wm8994 codec chip init failed\n", __func__); - return ret; - } - - return _wm8994_init(&wm8994_info, aif_id, sampling_rate, mclk_freq, - bits_per_sample, channels); -} -#endif - static int wm8994_set_params(struct udevice *dev, int interface, int rate, int mclk_freq, int bits_per_sample, uint channels) { diff --git a/include/sound.h b/include/sound.h index c94d2c37265..02acefd34f0 100644 --- a/include/sound.h +++ b/include/sound.h @@ -45,14 +45,6 @@ struct sound_uc_priv { void sound_create_square_wave(uint sample_rate, unsigned short *data, int size, uint freq); -/* - * Initialises audio sub system - * @param blob Pointer of device tree node or NULL if none. - * @return int value 0 for success, -1 for error - */ -int sound_init(const void *blob); - -#ifdef CONFIG_DM_SOUND /* * The sound uclass brings together a data transport (currently only I2C) and a * codec (currently connected over I2C). @@ -101,14 +93,4 @@ int sound_beep(struct udevice *dev, int msecs, int frequency_hz); */ int sound_find_codec_i2s(struct udevice *dev); -#else -/* - * plays the pcm data buffer in pcm_data.h through i2s1 to make the - * sine wave sound - * - * @return int 0 for success, -1 for error - */ -int sound_play(uint32_t msec, uint32_t frequency); -#endif /* CONFIG_DM_SOUND */ - #endif /* __SOUND__H__ */ diff --git a/test/dm/Makefile b/test/dm/Makefile index 73f5dcf739e..6b451060d8a 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_UT_DM) += test-uclass.o # subsystem you must add sandbox tests here. obj-$(CONFIG_UT_DM) += core.o ifneq ($(CONFIG_SANDBOX),) -obj-$(CONFIG_DM_SOUND) += audio.o +obj-$(CONFIG_SOUND) += audio.o obj-$(CONFIG_BLK) += blk.o obj-$(CONFIG_BOARD) += board.o obj-$(CONFIG_CLK) += clk.o @@ -22,7 +22,7 @@ obj-$(CONFIG_FIRMWARE) += firmware.o obj-$(CONFIG_DM_GPIO) += gpio.o obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock.o obj-$(CONFIG_DM_I2C) += i2c.o -obj-$(CONFIG_DM_SOUND) += i2s.o +obj-$(CONFIG_SOUND) += i2s.o obj-$(CONFIG_LED) += led.o obj-$(CONFIG_DM_MAILBOX) += mailbox.o obj-$(CONFIG_DM_MMC) += mmc.o @@ -55,7 +55,7 @@ obj-$(CONFIG_AXI) += axi.o obj-$(CONFIG_MISC) += misc.o obj-$(CONFIG_DM_SERIAL) += serial.o obj-$(CONFIG_CPU) += cpu.o -obj-$(CONFIG_DM_SOUND) += sound.o +obj-$(CONFIG_SOUND) += sound.o obj-$(CONFIG_TEE) += tee.o obj-$(CONFIG_VIRTIO_SANDBOX) += virtio.o obj-$(CONFIG_DMA) += dma.o -- cgit v1.3.1 From f987177db9c988142032ed8142a093cce2378a90 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 10 Dec 2018 10:37:51 -0700 Subject: dm: sound: Use the correct number of channels for sound At present the 'beep' sound generates a waveform for only one channel even if two are being used. This means that the beep is twice the frequency it should be. Correct this by making it a parameter. The fix in a previous commit was correct for sandbox but not for other boards. Fixes: 03f11e87a8 ("sound: Correct data output in sound_create_square_wave()") Signed-off-by: Simon Glass --- drivers/sound/sound-uclass.c | 2 +- drivers/sound/sound.c | 11 +++++++---- include/sound.h | 11 ++++++----- 3 files changed, 14 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/sound/sound-uclass.c b/drivers/sound/sound-uclass.c index 71e753cb993..2b836268896 100644 --- a/drivers/sound/sound-uclass.c +++ b/drivers/sound/sound-uclass.c @@ -53,7 +53,7 @@ int sound_beep(struct udevice *dev, int msecs, int frequency_hz) } sound_create_square_wave(i2s_uc_priv->samplingrate, data, data_size, - frequency_hz); + frequency_hz, i2s_uc_priv->channels); while (msecs >= 1000) { ret = sound_play(dev, data, data_size); diff --git a/drivers/sound/sound.c b/drivers/sound/sound.c index 4f0ad0d8f0d..dd3f9db4f75 100644 --- a/drivers/sound/sound.c +++ b/drivers/sound/sound.c @@ -8,7 +8,7 @@ #include void sound_create_square_wave(uint sample_rate, unsigned short *data, int size, - uint freq) + uint freq, uint channels) { const unsigned short amplitude = 16000; /* between 1 and 32767 */ const int period = freq ? sample_rate / freq : 0; @@ -21,14 +21,17 @@ void sound_create_square_wave(uint sample_rate, unsigned short *data, int size, size--; while (size) { - int i; + int i, j; + for (i = 0; size && i < half; i++) { size -= 2; - *data++ = amplitude; + for (j = 0; j < channels; j++) + *data++ = amplitude; } for (i = 0; size && i < period - half; i++) { size -= 2; - *data++ = -amplitude; + for (j = 0; j < channels; j++) + *data++ = -amplitude; } } } diff --git a/include/sound.h b/include/sound.h index 02acefd34f0..b7959cc2607 100644 --- a/include/sound.h +++ b/include/sound.h @@ -37,13 +37,14 @@ struct sound_uc_priv { /** * Generates square wave sound data for 1 second * - * @param sample_rate Sample rate in Hz - * @param data data buffer pointer - * @param size size of the buffer in bytes - * @param freq frequency of the wave + * @sample_rate: Sample rate in Hz + * @data: data buffer pointer + * @size: size of the buffer in bytes + * @freq: frequency of the wave + * @channels: Number of channels to use */ void sound_create_square_wave(uint sample_rate, unsigned short *data, int size, - uint freq); + uint freq, uint channels); /* * The sound uclass brings together a data transport (currently only I2C) and a -- cgit v1.3.1