From patchwork Mon Dec 3 11:37:39 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1006867 X-Patchwork-Delegate: sjg@chromium.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=chromium.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="QS9m0hrG"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 437k5v0vR8z9s9G for ; Mon, 3 Dec 2018 22:58:11 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id B0282C222DF; Mon, 3 Dec 2018 11:51:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=RCVD_IN_DNSWL_BLOCKED, T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id CE7F1C22488; Mon, 3 Dec 2018 11:40:00 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 81546C22456; Mon, 3 Dec 2018 11:39:00 +0000 (UTC) Received: from mail-oi1-f199.google.com (mail-oi1-f199.google.com [209.85.167.199]) by lists.denx.de (Postfix) with ESMTPS id 3EC27C2218E for ; Mon, 3 Dec 2018 11:38:52 +0000 (UTC) Received: by mail-oi1-f199.google.com with SMTP id e141so7971849oig.11 for ; Mon, 03 Dec 2018 03:38:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=TnXjzjDUwAtQxlQAFcJnDlSxP2pgQaU1MUW3NVhM4VE=; b=QS9m0hrG2PriQv8U8vmsGmqAdYcZtwnH9JZSS4WXMfG3ltJNH9au1EV5uxhiEFnZ90 4cT30sbPf2DMO15bEja9yScQBUX/q04OYGG1mNhNMZMyiOS9Zi0prW0khKGsPKq4lBUv nEb5JPaGGH15jFsDFVAJJ7IwZgtyFCgIOOZd0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=TnXjzjDUwAtQxlQAFcJnDlSxP2pgQaU1MUW3NVhM4VE=; b=ApLw3iJ89LA6QqA6rXcac5k0zC167YPDnhorfbqubiPiWEenDOvLXbmRHCNjan1jHP atY90ToRPF0rfvW/pFsvUhJU+jfnMbcCNnT2mcYttcBH1uLmQevLTk3uuujP3h4YPqyy nuWppCwuz9OVNL86dLMCVQZlR8JxUVI6xgUEHmpTMAttZQ4VSkBGcPhYytQXcJZ5dDCw y9JdpZn8lwidGavwZ+CdY+X0FtuY+ix8GMn7v1I5bL4BiHyCMBv+Bctz0IsmWXkeim1g 5rgF9vd0FrZrlPn0DqIjiWMgvSRw1R7Mg7zLSYrgdMozPY/ykV6+/WOCbKoNcHVG0knU fDsg== X-Gm-Message-State: AA+aEWa5o9PwdKKlfgTdNBmF66oah9/t5CQC7KflIOQn7gkqEFSZSpfh 4F1PJD/qS/lTKC3QqOcHPJjGORH9yMN3nkZh X-Google-Smtp-Source: AFSGD/Vm9Yj71VI+tFoq2rN5V2NnWan1EdbQ3PD5/9Wh4O7nK9s31lxwuumDyMfmMmIrKQtnzSjziFM8TKFc8n+D X-Received: by 2002:aca:f587:: with SMTP id t129mr13641212oih.9.1543837131200; Mon, 03 Dec 2018 03:38:51 -0800 (PST) Date: Mon, 3 Dec 2018 04:37:39 -0700 In-Reply-To: <20181203113746.218103-1-sjg@chromium.org> Message-Id: <20181203113746.218103-24-sjg@chromium.org> Mime-Version: 1.0 References: <20181203113746.218103-1-sjg@chromium.org> X-Mailer: git-send-email 2.20.0.rc1.387.gf8505762e3-goog From: Simon Glass To: U-Boot Mailing List Cc: Eugeniu Rosca , Joe Hershberger Subject: [U-Boot] [PATCH 23/30] dm: sound: Create a uclass for i2s X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" 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 | 58 ++++++++++++++++++++++++++++++++- include/dm/uclass-id.h | 1 + include/i2s.h | 25 ++++++++++++++ test/dm/Makefile | 1 + test/dm/i2s.c | 32 ++++++++++++++++++ 9 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 drivers/sound/i2s-uclass.c create mode 100644 test/dm/i2s.c diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 4e4eaa2dceb..01ab409b388 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..e2b4b2322dd --- /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, uint *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..59931ec0a12 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,32 @@ static int sandbox_codec_set_params(struct udevice *dev, int interface, return 0; } +static int sandbox_i2s_tx_data(struct udevice *dev, u32 *data, uint data_size) +{ + struct sandbox_i2s_priv *priv = dev_get_priv(dev); + + while (data_size-- > 0) + priv->sum += *data++; + + 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 +113,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 4c2051a4c6f..ffafe08a4fe 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -46,6 +46,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_AXI, /* AXI bus */ UCLASS_IRQ, /* Interrupt controller */ diff --git a/include/i2s.h b/include/i2s.h index f23862ca040..4839f13458b 100644 --- a/include/i2s.h +++ b/include/i2s.h @@ -87,6 +87,31 @@ 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 units of 32-bit words + * @return 0 if OK, -ve on error + */ + int (*tx_data)(struct udevice *dev, u32 *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 units of 32-bit words + * @return 0 if OK, -ve on error + */ +int i2s_tx_data(struct udevice *dev, u32 *data, uint data_size); + /* * Sends the given data through i2s tx * diff --git a/test/dm/Makefile b/test/dm/Makefile index 592d992a75a..07d6f97cb77 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_DM_ETH) += eth.o obj-$(CONFIG_FIRMWARE) += firmware.o obj-$(CONFIG_DM_GPIO) += gpio.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..523bf89d08b --- /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; + u32 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);