162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) ST-Ericsson SA 2012 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: Ola Lilja <ola.o.lilja@stericsson.com>, 662306a36Sopenharmony_ci * Roger Nilsson <roger.xr.nilsson@stericsson.com>, 762306a36Sopenharmony_ci * Sandeep Kaushik <sandeep.kaushik@st.com> 862306a36Sopenharmony_ci * for ST-Ericsson. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/platform_device.h> 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/io.h> 1662306a36Sopenharmony_ci#include <linux/of.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <sound/soc.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "ux500_msp_i2s.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci /* Protocol desciptors */ 2362306a36Sopenharmony_cistatic const struct msp_protdesc prot_descs[] = { 2462306a36Sopenharmony_ci { /* I2S */ 2562306a36Sopenharmony_ci MSP_SINGLE_PHASE, 2662306a36Sopenharmony_ci MSP_SINGLE_PHASE, 2762306a36Sopenharmony_ci MSP_PHASE2_START_MODE_IMEDIATE, 2862306a36Sopenharmony_ci MSP_PHASE2_START_MODE_IMEDIATE, 2962306a36Sopenharmony_ci MSP_BTF_MS_BIT_FIRST, 3062306a36Sopenharmony_ci MSP_BTF_MS_BIT_FIRST, 3162306a36Sopenharmony_ci MSP_FRAME_LEN_1, 3262306a36Sopenharmony_ci MSP_FRAME_LEN_1, 3362306a36Sopenharmony_ci MSP_FRAME_LEN_1, 3462306a36Sopenharmony_ci MSP_FRAME_LEN_1, 3562306a36Sopenharmony_ci MSP_ELEM_LEN_32, 3662306a36Sopenharmony_ci MSP_ELEM_LEN_32, 3762306a36Sopenharmony_ci MSP_ELEM_LEN_32, 3862306a36Sopenharmony_ci MSP_ELEM_LEN_32, 3962306a36Sopenharmony_ci MSP_DELAY_1, 4062306a36Sopenharmony_ci MSP_DELAY_1, 4162306a36Sopenharmony_ci MSP_RISING_EDGE, 4262306a36Sopenharmony_ci MSP_FALLING_EDGE, 4362306a36Sopenharmony_ci MSP_FSYNC_POL_ACT_LO, 4462306a36Sopenharmony_ci MSP_FSYNC_POL_ACT_LO, 4562306a36Sopenharmony_ci MSP_SWAP_NONE, 4662306a36Sopenharmony_ci MSP_SWAP_NONE, 4762306a36Sopenharmony_ci MSP_COMPRESS_MODE_LINEAR, 4862306a36Sopenharmony_ci MSP_EXPAND_MODE_LINEAR, 4962306a36Sopenharmony_ci MSP_FSYNC_IGNORE, 5062306a36Sopenharmony_ci 31, 5162306a36Sopenharmony_ci 15, 5262306a36Sopenharmony_ci 32, 5362306a36Sopenharmony_ci }, { /* PCM */ 5462306a36Sopenharmony_ci MSP_DUAL_PHASE, 5562306a36Sopenharmony_ci MSP_DUAL_PHASE, 5662306a36Sopenharmony_ci MSP_PHASE2_START_MODE_FSYNC, 5762306a36Sopenharmony_ci MSP_PHASE2_START_MODE_FSYNC, 5862306a36Sopenharmony_ci MSP_BTF_MS_BIT_FIRST, 5962306a36Sopenharmony_ci MSP_BTF_MS_BIT_FIRST, 6062306a36Sopenharmony_ci MSP_FRAME_LEN_1, 6162306a36Sopenharmony_ci MSP_FRAME_LEN_1, 6262306a36Sopenharmony_ci MSP_FRAME_LEN_1, 6362306a36Sopenharmony_ci MSP_FRAME_LEN_1, 6462306a36Sopenharmony_ci MSP_ELEM_LEN_16, 6562306a36Sopenharmony_ci MSP_ELEM_LEN_16, 6662306a36Sopenharmony_ci MSP_ELEM_LEN_16, 6762306a36Sopenharmony_ci MSP_ELEM_LEN_16, 6862306a36Sopenharmony_ci MSP_DELAY_0, 6962306a36Sopenharmony_ci MSP_DELAY_0, 7062306a36Sopenharmony_ci MSP_RISING_EDGE, 7162306a36Sopenharmony_ci MSP_FALLING_EDGE, 7262306a36Sopenharmony_ci MSP_FSYNC_POL_ACT_HI, 7362306a36Sopenharmony_ci MSP_FSYNC_POL_ACT_HI, 7462306a36Sopenharmony_ci MSP_SWAP_NONE, 7562306a36Sopenharmony_ci MSP_SWAP_NONE, 7662306a36Sopenharmony_ci MSP_COMPRESS_MODE_LINEAR, 7762306a36Sopenharmony_ci MSP_EXPAND_MODE_LINEAR, 7862306a36Sopenharmony_ci MSP_FSYNC_IGNORE, 7962306a36Sopenharmony_ci 255, 8062306a36Sopenharmony_ci 0, 8162306a36Sopenharmony_ci 256, 8262306a36Sopenharmony_ci }, { /* Companded PCM */ 8362306a36Sopenharmony_ci MSP_SINGLE_PHASE, 8462306a36Sopenharmony_ci MSP_SINGLE_PHASE, 8562306a36Sopenharmony_ci MSP_PHASE2_START_MODE_FSYNC, 8662306a36Sopenharmony_ci MSP_PHASE2_START_MODE_FSYNC, 8762306a36Sopenharmony_ci MSP_BTF_MS_BIT_FIRST, 8862306a36Sopenharmony_ci MSP_BTF_MS_BIT_FIRST, 8962306a36Sopenharmony_ci MSP_FRAME_LEN_1, 9062306a36Sopenharmony_ci MSP_FRAME_LEN_1, 9162306a36Sopenharmony_ci MSP_FRAME_LEN_1, 9262306a36Sopenharmony_ci MSP_FRAME_LEN_1, 9362306a36Sopenharmony_ci MSP_ELEM_LEN_8, 9462306a36Sopenharmony_ci MSP_ELEM_LEN_8, 9562306a36Sopenharmony_ci MSP_ELEM_LEN_8, 9662306a36Sopenharmony_ci MSP_ELEM_LEN_8, 9762306a36Sopenharmony_ci MSP_DELAY_0, 9862306a36Sopenharmony_ci MSP_DELAY_0, 9962306a36Sopenharmony_ci MSP_RISING_EDGE, 10062306a36Sopenharmony_ci MSP_RISING_EDGE, 10162306a36Sopenharmony_ci MSP_FSYNC_POL_ACT_HI, 10262306a36Sopenharmony_ci MSP_FSYNC_POL_ACT_HI, 10362306a36Sopenharmony_ci MSP_SWAP_NONE, 10462306a36Sopenharmony_ci MSP_SWAP_NONE, 10562306a36Sopenharmony_ci MSP_COMPRESS_MODE_LINEAR, 10662306a36Sopenharmony_ci MSP_EXPAND_MODE_LINEAR, 10762306a36Sopenharmony_ci MSP_FSYNC_IGNORE, 10862306a36Sopenharmony_ci 255, 10962306a36Sopenharmony_ci 0, 11062306a36Sopenharmony_ci 256, 11162306a36Sopenharmony_ci }, 11262306a36Sopenharmony_ci}; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic void set_prot_desc_tx(struct ux500_msp *msp, 11562306a36Sopenharmony_ci struct msp_protdesc *protdesc, 11662306a36Sopenharmony_ci enum msp_data_size data_size) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci u32 temp_reg = 0; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci temp_reg |= MSP_P2_ENABLE_BIT(protdesc->tx_phase_mode); 12162306a36Sopenharmony_ci temp_reg |= MSP_P2_START_MODE_BIT(protdesc->tx_phase2_start_mode); 12262306a36Sopenharmony_ci temp_reg |= MSP_P1_FRAME_LEN_BITS(protdesc->tx_frame_len_1); 12362306a36Sopenharmony_ci temp_reg |= MSP_P2_FRAME_LEN_BITS(protdesc->tx_frame_len_2); 12462306a36Sopenharmony_ci if (msp->def_elem_len) { 12562306a36Sopenharmony_ci temp_reg |= MSP_P1_ELEM_LEN_BITS(protdesc->tx_elem_len_1); 12662306a36Sopenharmony_ci temp_reg |= MSP_P2_ELEM_LEN_BITS(protdesc->tx_elem_len_2); 12762306a36Sopenharmony_ci } else { 12862306a36Sopenharmony_ci temp_reg |= MSP_P1_ELEM_LEN_BITS(data_size); 12962306a36Sopenharmony_ci temp_reg |= MSP_P2_ELEM_LEN_BITS(data_size); 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci temp_reg |= MSP_DATA_DELAY_BITS(protdesc->tx_data_delay); 13262306a36Sopenharmony_ci temp_reg |= MSP_SET_ENDIANNES_BIT(protdesc->tx_byte_order); 13362306a36Sopenharmony_ci temp_reg |= MSP_FSYNC_POL(protdesc->tx_fsync_pol); 13462306a36Sopenharmony_ci temp_reg |= MSP_DATA_WORD_SWAP(protdesc->tx_half_word_swap); 13562306a36Sopenharmony_ci temp_reg |= MSP_SET_COMPANDING_MODE(protdesc->compression_mode); 13662306a36Sopenharmony_ci temp_reg |= MSP_SET_FSYNC_IGNORE(protdesc->frame_sync_ignore); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci writel(temp_reg, msp->registers + MSP_TCF); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic void set_prot_desc_rx(struct ux500_msp *msp, 14262306a36Sopenharmony_ci struct msp_protdesc *protdesc, 14362306a36Sopenharmony_ci enum msp_data_size data_size) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci u32 temp_reg = 0; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci temp_reg |= MSP_P2_ENABLE_BIT(protdesc->rx_phase_mode); 14862306a36Sopenharmony_ci temp_reg |= MSP_P2_START_MODE_BIT(protdesc->rx_phase2_start_mode); 14962306a36Sopenharmony_ci temp_reg |= MSP_P1_FRAME_LEN_BITS(protdesc->rx_frame_len_1); 15062306a36Sopenharmony_ci temp_reg |= MSP_P2_FRAME_LEN_BITS(protdesc->rx_frame_len_2); 15162306a36Sopenharmony_ci if (msp->def_elem_len) { 15262306a36Sopenharmony_ci temp_reg |= MSP_P1_ELEM_LEN_BITS(protdesc->rx_elem_len_1); 15362306a36Sopenharmony_ci temp_reg |= MSP_P2_ELEM_LEN_BITS(protdesc->rx_elem_len_2); 15462306a36Sopenharmony_ci } else { 15562306a36Sopenharmony_ci temp_reg |= MSP_P1_ELEM_LEN_BITS(data_size); 15662306a36Sopenharmony_ci temp_reg |= MSP_P2_ELEM_LEN_BITS(data_size); 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci temp_reg |= MSP_DATA_DELAY_BITS(protdesc->rx_data_delay); 16062306a36Sopenharmony_ci temp_reg |= MSP_SET_ENDIANNES_BIT(protdesc->rx_byte_order); 16162306a36Sopenharmony_ci temp_reg |= MSP_FSYNC_POL(protdesc->rx_fsync_pol); 16262306a36Sopenharmony_ci temp_reg |= MSP_DATA_WORD_SWAP(protdesc->rx_half_word_swap); 16362306a36Sopenharmony_ci temp_reg |= MSP_SET_COMPANDING_MODE(protdesc->expansion_mode); 16462306a36Sopenharmony_ci temp_reg |= MSP_SET_FSYNC_IGNORE(protdesc->frame_sync_ignore); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci writel(temp_reg, msp->registers + MSP_RCF); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic int configure_protocol(struct ux500_msp *msp, 17062306a36Sopenharmony_ci struct ux500_msp_config *config) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci struct msp_protdesc *protdesc; 17362306a36Sopenharmony_ci enum msp_data_size data_size; 17462306a36Sopenharmony_ci u32 temp_reg = 0; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci data_size = config->data_size; 17762306a36Sopenharmony_ci msp->def_elem_len = config->def_elem_len; 17862306a36Sopenharmony_ci if (config->default_protdesc == 1) { 17962306a36Sopenharmony_ci if (config->protocol >= MSP_INVALID_PROTOCOL) { 18062306a36Sopenharmony_ci dev_err(msp->dev, "%s: ERROR: Invalid protocol!\n", 18162306a36Sopenharmony_ci __func__); 18262306a36Sopenharmony_ci return -EINVAL; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci protdesc = 18562306a36Sopenharmony_ci (struct msp_protdesc *)&prot_descs[config->protocol]; 18662306a36Sopenharmony_ci } else { 18762306a36Sopenharmony_ci protdesc = (struct msp_protdesc *)&config->protdesc; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if (data_size < MSP_DATA_BITS_DEFAULT || data_size > MSP_DATA_BITS_32) { 19162306a36Sopenharmony_ci dev_err(msp->dev, 19262306a36Sopenharmony_ci "%s: ERROR: Invalid data-size requested (data_size = %d)!\n", 19362306a36Sopenharmony_ci __func__, data_size); 19462306a36Sopenharmony_ci return -EINVAL; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (config->direction & MSP_DIR_TX) 19862306a36Sopenharmony_ci set_prot_desc_tx(msp, protdesc, data_size); 19962306a36Sopenharmony_ci if (config->direction & MSP_DIR_RX) 20062306a36Sopenharmony_ci set_prot_desc_rx(msp, protdesc, data_size); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* The code below should not be separated. */ 20362306a36Sopenharmony_ci temp_reg = readl(msp->registers + MSP_GCR) & ~TX_CLK_POL_RISING; 20462306a36Sopenharmony_ci temp_reg |= MSP_TX_CLKPOL_BIT(~protdesc->tx_clk_pol); 20562306a36Sopenharmony_ci writel(temp_reg, msp->registers + MSP_GCR); 20662306a36Sopenharmony_ci temp_reg = readl(msp->registers + MSP_GCR) & ~RX_CLK_POL_RISING; 20762306a36Sopenharmony_ci temp_reg |= MSP_RX_CLKPOL_BIT(protdesc->rx_clk_pol); 20862306a36Sopenharmony_ci writel(temp_reg, msp->registers + MSP_GCR); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci return 0; 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic int setup_bitclk(struct ux500_msp *msp, struct ux500_msp_config *config) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci u32 reg_val_GCR; 21662306a36Sopenharmony_ci u32 frame_per = 0; 21762306a36Sopenharmony_ci u32 sck_div = 0; 21862306a36Sopenharmony_ci u32 frame_width = 0; 21962306a36Sopenharmony_ci u32 temp_reg = 0; 22062306a36Sopenharmony_ci struct msp_protdesc *protdesc = NULL; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci reg_val_GCR = readl(msp->registers + MSP_GCR); 22362306a36Sopenharmony_ci writel(reg_val_GCR & ~SRG_ENABLE, msp->registers + MSP_GCR); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (config->default_protdesc) 22662306a36Sopenharmony_ci protdesc = 22762306a36Sopenharmony_ci (struct msp_protdesc *)&prot_descs[config->protocol]; 22862306a36Sopenharmony_ci else 22962306a36Sopenharmony_ci protdesc = (struct msp_protdesc *)&config->protdesc; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci switch (config->protocol) { 23262306a36Sopenharmony_ci case MSP_PCM_PROTOCOL: 23362306a36Sopenharmony_ci case MSP_PCM_COMPAND_PROTOCOL: 23462306a36Sopenharmony_ci frame_width = protdesc->frame_width; 23562306a36Sopenharmony_ci sck_div = config->f_inputclk / (config->frame_freq * 23662306a36Sopenharmony_ci (protdesc->clocks_per_frame)); 23762306a36Sopenharmony_ci frame_per = protdesc->frame_period; 23862306a36Sopenharmony_ci break; 23962306a36Sopenharmony_ci case MSP_I2S_PROTOCOL: 24062306a36Sopenharmony_ci frame_width = protdesc->frame_width; 24162306a36Sopenharmony_ci sck_div = config->f_inputclk / (config->frame_freq * 24262306a36Sopenharmony_ci (protdesc->clocks_per_frame)); 24362306a36Sopenharmony_ci frame_per = protdesc->frame_period; 24462306a36Sopenharmony_ci break; 24562306a36Sopenharmony_ci default: 24662306a36Sopenharmony_ci dev_err(msp->dev, "%s: ERROR: Unknown protocol (%d)!\n", 24762306a36Sopenharmony_ci __func__, 24862306a36Sopenharmony_ci config->protocol); 24962306a36Sopenharmony_ci return -EINVAL; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci temp_reg = (sck_div - 1) & SCK_DIV_MASK; 25362306a36Sopenharmony_ci temp_reg |= FRAME_WIDTH_BITS(frame_width); 25462306a36Sopenharmony_ci temp_reg |= FRAME_PERIOD_BITS(frame_per); 25562306a36Sopenharmony_ci writel(temp_reg, msp->registers + MSP_SRG); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci msp->f_bitclk = (config->f_inputclk)/(sck_div + 1); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* Enable bit-clock */ 26062306a36Sopenharmony_ci udelay(100); 26162306a36Sopenharmony_ci reg_val_GCR = readl(msp->registers + MSP_GCR); 26262306a36Sopenharmony_ci writel(reg_val_GCR | SRG_ENABLE, msp->registers + MSP_GCR); 26362306a36Sopenharmony_ci udelay(100); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return 0; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic int configure_multichannel(struct ux500_msp *msp, 26962306a36Sopenharmony_ci struct ux500_msp_config *config) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci struct msp_protdesc *protdesc; 27262306a36Sopenharmony_ci struct msp_multichannel_config *mcfg; 27362306a36Sopenharmony_ci u32 reg_val_MCR; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (config->default_protdesc == 1) { 27662306a36Sopenharmony_ci if (config->protocol >= MSP_INVALID_PROTOCOL) { 27762306a36Sopenharmony_ci dev_err(msp->dev, 27862306a36Sopenharmony_ci "%s: ERROR: Invalid protocol (%d)!\n", 27962306a36Sopenharmony_ci __func__, config->protocol); 28062306a36Sopenharmony_ci return -EINVAL; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci protdesc = (struct msp_protdesc *) 28362306a36Sopenharmony_ci &prot_descs[config->protocol]; 28462306a36Sopenharmony_ci } else { 28562306a36Sopenharmony_ci protdesc = (struct msp_protdesc *)&config->protdesc; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci mcfg = &config->multichannel_config; 28962306a36Sopenharmony_ci if (mcfg->tx_multichannel_enable) { 29062306a36Sopenharmony_ci if (protdesc->tx_phase_mode == MSP_SINGLE_PHASE) { 29162306a36Sopenharmony_ci reg_val_MCR = readl(msp->registers + MSP_MCR); 29262306a36Sopenharmony_ci writel(reg_val_MCR | (mcfg->tx_multichannel_enable ? 29362306a36Sopenharmony_ci 1 << TMCEN_BIT : 0), 29462306a36Sopenharmony_ci msp->registers + MSP_MCR); 29562306a36Sopenharmony_ci writel(mcfg->tx_channel_0_enable, 29662306a36Sopenharmony_ci msp->registers + MSP_TCE0); 29762306a36Sopenharmony_ci writel(mcfg->tx_channel_1_enable, 29862306a36Sopenharmony_ci msp->registers + MSP_TCE1); 29962306a36Sopenharmony_ci writel(mcfg->tx_channel_2_enable, 30062306a36Sopenharmony_ci msp->registers + MSP_TCE2); 30162306a36Sopenharmony_ci writel(mcfg->tx_channel_3_enable, 30262306a36Sopenharmony_ci msp->registers + MSP_TCE3); 30362306a36Sopenharmony_ci } else { 30462306a36Sopenharmony_ci dev_err(msp->dev, 30562306a36Sopenharmony_ci "%s: ERROR: Only single-phase supported (TX-mode: %d)!\n", 30662306a36Sopenharmony_ci __func__, protdesc->tx_phase_mode); 30762306a36Sopenharmony_ci return -EINVAL; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci if (mcfg->rx_multichannel_enable) { 31162306a36Sopenharmony_ci if (protdesc->rx_phase_mode == MSP_SINGLE_PHASE) { 31262306a36Sopenharmony_ci reg_val_MCR = readl(msp->registers + MSP_MCR); 31362306a36Sopenharmony_ci writel(reg_val_MCR | (mcfg->rx_multichannel_enable ? 31462306a36Sopenharmony_ci 1 << RMCEN_BIT : 0), 31562306a36Sopenharmony_ci msp->registers + MSP_MCR); 31662306a36Sopenharmony_ci writel(mcfg->rx_channel_0_enable, 31762306a36Sopenharmony_ci msp->registers + MSP_RCE0); 31862306a36Sopenharmony_ci writel(mcfg->rx_channel_1_enable, 31962306a36Sopenharmony_ci msp->registers + MSP_RCE1); 32062306a36Sopenharmony_ci writel(mcfg->rx_channel_2_enable, 32162306a36Sopenharmony_ci msp->registers + MSP_RCE2); 32262306a36Sopenharmony_ci writel(mcfg->rx_channel_3_enable, 32362306a36Sopenharmony_ci msp->registers + MSP_RCE3); 32462306a36Sopenharmony_ci } else { 32562306a36Sopenharmony_ci dev_err(msp->dev, 32662306a36Sopenharmony_ci "%s: ERROR: Only single-phase supported (RX-mode: %d)!\n", 32762306a36Sopenharmony_ci __func__, protdesc->rx_phase_mode); 32862306a36Sopenharmony_ci return -EINVAL; 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci if (mcfg->rx_comparison_enable_mode) { 33162306a36Sopenharmony_ci reg_val_MCR = readl(msp->registers + MSP_MCR); 33262306a36Sopenharmony_ci writel(reg_val_MCR | 33362306a36Sopenharmony_ci (mcfg->rx_comparison_enable_mode << RCMPM_BIT), 33462306a36Sopenharmony_ci msp->registers + MSP_MCR); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci writel(mcfg->comparison_mask, 33762306a36Sopenharmony_ci msp->registers + MSP_RCM); 33862306a36Sopenharmony_ci writel(mcfg->comparison_value, 33962306a36Sopenharmony_ci msp->registers + MSP_RCV); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return 0; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci int status = 0; 35062306a36Sopenharmony_ci u32 reg_val_DMACR, reg_val_GCR; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* Configure msp with protocol dependent settings */ 35362306a36Sopenharmony_ci configure_protocol(msp, config); 35462306a36Sopenharmony_ci setup_bitclk(msp, config); 35562306a36Sopenharmony_ci if (config->multichannel_configured == 1) { 35662306a36Sopenharmony_ci status = configure_multichannel(msp, config); 35762306a36Sopenharmony_ci if (status) 35862306a36Sopenharmony_ci dev_warn(msp->dev, 35962306a36Sopenharmony_ci "%s: WARN: configure_multichannel failed (%d)!\n", 36062306a36Sopenharmony_ci __func__, status); 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci reg_val_DMACR = readl(msp->registers + MSP_DMACR); 36462306a36Sopenharmony_ci if (config->direction & MSP_DIR_RX) 36562306a36Sopenharmony_ci reg_val_DMACR |= RX_DMA_ENABLE; 36662306a36Sopenharmony_ci if (config->direction & MSP_DIR_TX) 36762306a36Sopenharmony_ci reg_val_DMACR |= TX_DMA_ENABLE; 36862306a36Sopenharmony_ci writel(reg_val_DMACR, msp->registers + MSP_DMACR); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci writel(config->iodelay, msp->registers + MSP_IODLY); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* Enable frame generation logic */ 37362306a36Sopenharmony_ci reg_val_GCR = readl(msp->registers + MSP_GCR); 37462306a36Sopenharmony_ci writel(reg_val_GCR | FRAME_GEN_ENABLE, msp->registers + MSP_GCR); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci return status; 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic void flush_fifo_rx(struct ux500_msp *msp) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci u32 reg_val_GCR, reg_val_FLR; 38262306a36Sopenharmony_ci u32 limit = 32; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci reg_val_GCR = readl(msp->registers + MSP_GCR); 38562306a36Sopenharmony_ci writel(reg_val_GCR | RX_ENABLE, msp->registers + MSP_GCR); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci reg_val_FLR = readl(msp->registers + MSP_FLR); 38862306a36Sopenharmony_ci while (!(reg_val_FLR & RX_FIFO_EMPTY) && limit--) { 38962306a36Sopenharmony_ci readl(msp->registers + MSP_DR); 39062306a36Sopenharmony_ci reg_val_FLR = readl(msp->registers + MSP_FLR); 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci writel(reg_val_GCR, msp->registers + MSP_GCR); 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic void flush_fifo_tx(struct ux500_msp *msp) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci u32 reg_val_GCR, reg_val_FLR; 39962306a36Sopenharmony_ci u32 limit = 32; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci reg_val_GCR = readl(msp->registers + MSP_GCR); 40262306a36Sopenharmony_ci writel(reg_val_GCR | TX_ENABLE, msp->registers + MSP_GCR); 40362306a36Sopenharmony_ci writel(MSP_ITCR_ITEN | MSP_ITCR_TESTFIFO, msp->registers + MSP_ITCR); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci reg_val_FLR = readl(msp->registers + MSP_FLR); 40662306a36Sopenharmony_ci while (!(reg_val_FLR & TX_FIFO_EMPTY) && limit--) { 40762306a36Sopenharmony_ci readl(msp->registers + MSP_TSTDR); 40862306a36Sopenharmony_ci reg_val_FLR = readl(msp->registers + MSP_FLR); 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci writel(0x0, msp->registers + MSP_ITCR); 41162306a36Sopenharmony_ci writel(reg_val_GCR, msp->registers + MSP_GCR); 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ciint ux500_msp_i2s_open(struct ux500_msp *msp, 41562306a36Sopenharmony_ci struct ux500_msp_config *config) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci u32 old_reg, new_reg, mask; 41862306a36Sopenharmony_ci int res; 41962306a36Sopenharmony_ci unsigned int tx_sel, rx_sel, tx_busy, rx_busy; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (in_interrupt()) { 42262306a36Sopenharmony_ci dev_err(msp->dev, 42362306a36Sopenharmony_ci "%s: ERROR: Open called in interrupt context!\n", 42462306a36Sopenharmony_ci __func__); 42562306a36Sopenharmony_ci return -1; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci tx_sel = (config->direction & MSP_DIR_TX) > 0; 42962306a36Sopenharmony_ci rx_sel = (config->direction & MSP_DIR_RX) > 0; 43062306a36Sopenharmony_ci if (!tx_sel && !rx_sel) { 43162306a36Sopenharmony_ci dev_err(msp->dev, "%s: Error: No direction selected!\n", 43262306a36Sopenharmony_ci __func__); 43362306a36Sopenharmony_ci return -EINVAL; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci tx_busy = (msp->dir_busy & MSP_DIR_TX) > 0; 43762306a36Sopenharmony_ci rx_busy = (msp->dir_busy & MSP_DIR_RX) > 0; 43862306a36Sopenharmony_ci if (tx_busy && tx_sel) { 43962306a36Sopenharmony_ci dev_err(msp->dev, "%s: Error: TX is in use!\n", __func__); 44062306a36Sopenharmony_ci return -EBUSY; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci if (rx_busy && rx_sel) { 44362306a36Sopenharmony_ci dev_err(msp->dev, "%s: Error: RX is in use!\n", __func__); 44462306a36Sopenharmony_ci return -EBUSY; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci msp->dir_busy |= (tx_sel ? MSP_DIR_TX : 0) | (rx_sel ? MSP_DIR_RX : 0); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* First do the global config register */ 45062306a36Sopenharmony_ci mask = RX_CLK_SEL_MASK | TX_CLK_SEL_MASK | RX_FSYNC_MASK | 45162306a36Sopenharmony_ci TX_FSYNC_MASK | RX_SYNC_SEL_MASK | TX_SYNC_SEL_MASK | 45262306a36Sopenharmony_ci RX_FIFO_ENABLE_MASK | TX_FIFO_ENABLE_MASK | SRG_CLK_SEL_MASK | 45362306a36Sopenharmony_ci LOOPBACK_MASK | TX_EXTRA_DELAY_MASK; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci new_reg = (config->tx_clk_sel | config->rx_clk_sel | 45662306a36Sopenharmony_ci config->rx_fsync_pol | config->tx_fsync_pol | 45762306a36Sopenharmony_ci config->rx_fsync_sel | config->tx_fsync_sel | 45862306a36Sopenharmony_ci config->rx_fifo_config | config->tx_fifo_config | 45962306a36Sopenharmony_ci config->srg_clk_sel | config->loopback_enable | 46062306a36Sopenharmony_ci config->tx_data_enable); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci old_reg = readl(msp->registers + MSP_GCR); 46362306a36Sopenharmony_ci old_reg &= ~mask; 46462306a36Sopenharmony_ci new_reg |= old_reg; 46562306a36Sopenharmony_ci writel(new_reg, msp->registers + MSP_GCR); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci res = enable_msp(msp, config); 46862306a36Sopenharmony_ci if (res < 0) { 46962306a36Sopenharmony_ci dev_err(msp->dev, "%s: ERROR: enable_msp failed (%d)!\n", 47062306a36Sopenharmony_ci __func__, res); 47162306a36Sopenharmony_ci return -EBUSY; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci if (config->loopback_enable & 0x80) 47462306a36Sopenharmony_ci msp->loopback_enable = 1; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci /* Flush FIFOs */ 47762306a36Sopenharmony_ci flush_fifo_tx(msp); 47862306a36Sopenharmony_ci flush_fifo_rx(msp); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci msp->msp_state = MSP_STATE_CONFIGURED; 48162306a36Sopenharmony_ci return 0; 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic void disable_msp_rx(struct ux500_msp *msp) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci u32 reg_val_GCR, reg_val_DMACR, reg_val_IMSC; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci reg_val_GCR = readl(msp->registers + MSP_GCR); 48962306a36Sopenharmony_ci writel(reg_val_GCR & ~RX_ENABLE, msp->registers + MSP_GCR); 49062306a36Sopenharmony_ci reg_val_DMACR = readl(msp->registers + MSP_DMACR); 49162306a36Sopenharmony_ci writel(reg_val_DMACR & ~RX_DMA_ENABLE, msp->registers + MSP_DMACR); 49262306a36Sopenharmony_ci reg_val_IMSC = readl(msp->registers + MSP_IMSC); 49362306a36Sopenharmony_ci writel(reg_val_IMSC & 49462306a36Sopenharmony_ci ~(RX_SERVICE_INT | RX_OVERRUN_ERROR_INT), 49562306a36Sopenharmony_ci msp->registers + MSP_IMSC); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci msp->dir_busy &= ~MSP_DIR_RX; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic void disable_msp_tx(struct ux500_msp *msp) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci u32 reg_val_GCR, reg_val_DMACR, reg_val_IMSC; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci reg_val_GCR = readl(msp->registers + MSP_GCR); 50562306a36Sopenharmony_ci writel(reg_val_GCR & ~TX_ENABLE, msp->registers + MSP_GCR); 50662306a36Sopenharmony_ci reg_val_DMACR = readl(msp->registers + MSP_DMACR); 50762306a36Sopenharmony_ci writel(reg_val_DMACR & ~TX_DMA_ENABLE, msp->registers + MSP_DMACR); 50862306a36Sopenharmony_ci reg_val_IMSC = readl(msp->registers + MSP_IMSC); 50962306a36Sopenharmony_ci writel(reg_val_IMSC & 51062306a36Sopenharmony_ci ~(TX_SERVICE_INT | TX_UNDERRUN_ERR_INT), 51162306a36Sopenharmony_ci msp->registers + MSP_IMSC); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci msp->dir_busy &= ~MSP_DIR_TX; 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic int disable_msp(struct ux500_msp *msp, unsigned int dir) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci u32 reg_val_GCR; 51962306a36Sopenharmony_ci unsigned int disable_tx, disable_rx; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci reg_val_GCR = readl(msp->registers + MSP_GCR); 52262306a36Sopenharmony_ci disable_tx = dir & MSP_DIR_TX; 52362306a36Sopenharmony_ci disable_rx = dir & MSP_DIR_TX; 52462306a36Sopenharmony_ci if (disable_tx && disable_rx) { 52562306a36Sopenharmony_ci reg_val_GCR = readl(msp->registers + MSP_GCR); 52662306a36Sopenharmony_ci writel(reg_val_GCR | LOOPBACK_MASK, 52762306a36Sopenharmony_ci msp->registers + MSP_GCR); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci /* Flush TX-FIFO */ 53062306a36Sopenharmony_ci flush_fifo_tx(msp); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci /* Disable TX-channel */ 53362306a36Sopenharmony_ci writel((readl(msp->registers + MSP_GCR) & 53462306a36Sopenharmony_ci (~TX_ENABLE)), msp->registers + MSP_GCR); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* Flush RX-FIFO */ 53762306a36Sopenharmony_ci flush_fifo_rx(msp); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci /* Disable Loopback and Receive channel */ 54062306a36Sopenharmony_ci writel((readl(msp->registers + MSP_GCR) & 54162306a36Sopenharmony_ci (~(RX_ENABLE | LOOPBACK_MASK))), 54262306a36Sopenharmony_ci msp->registers + MSP_GCR); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci disable_msp_tx(msp); 54562306a36Sopenharmony_ci disable_msp_rx(msp); 54662306a36Sopenharmony_ci } else if (disable_tx) 54762306a36Sopenharmony_ci disable_msp_tx(msp); 54862306a36Sopenharmony_ci else if (disable_rx) 54962306a36Sopenharmony_ci disable_msp_rx(msp); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci return 0; 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ciint ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci u32 reg_val_GCR, enable_bit; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci if (msp->msp_state == MSP_STATE_IDLE) { 55962306a36Sopenharmony_ci dev_err(msp->dev, "%s: ERROR: MSP is not configured!\n", 56062306a36Sopenharmony_ci __func__); 56162306a36Sopenharmony_ci return -EINVAL; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci switch (cmd) { 56562306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 56662306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 56762306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 56862306a36Sopenharmony_ci if (direction == SNDRV_PCM_STREAM_PLAYBACK) 56962306a36Sopenharmony_ci enable_bit = TX_ENABLE; 57062306a36Sopenharmony_ci else 57162306a36Sopenharmony_ci enable_bit = RX_ENABLE; 57262306a36Sopenharmony_ci reg_val_GCR = readl(msp->registers + MSP_GCR); 57362306a36Sopenharmony_ci writel(reg_val_GCR | enable_bit, msp->registers + MSP_GCR); 57462306a36Sopenharmony_ci break; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 57762306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 57862306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 57962306a36Sopenharmony_ci if (direction == SNDRV_PCM_STREAM_PLAYBACK) 58062306a36Sopenharmony_ci disable_msp_tx(msp); 58162306a36Sopenharmony_ci else 58262306a36Sopenharmony_ci disable_msp_rx(msp); 58362306a36Sopenharmony_ci break; 58462306a36Sopenharmony_ci default: 58562306a36Sopenharmony_ci return -EINVAL; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci return 0; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ciint ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci int status = 0; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci dev_dbg(msp->dev, "%s: Enter (dir = 0x%01x).\n", __func__, dir); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci status = disable_msp(msp, dir); 59862306a36Sopenharmony_ci if (msp->dir_busy == 0) { 59962306a36Sopenharmony_ci /* disable sample rate and frame generators */ 60062306a36Sopenharmony_ci msp->msp_state = MSP_STATE_IDLE; 60162306a36Sopenharmony_ci writel((readl(msp->registers + MSP_GCR) & 60262306a36Sopenharmony_ci (~(FRAME_GEN_ENABLE | SRG_ENABLE))), 60362306a36Sopenharmony_ci msp->registers + MSP_GCR); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci writel(0, msp->registers + MSP_GCR); 60662306a36Sopenharmony_ci writel(0, msp->registers + MSP_TCF); 60762306a36Sopenharmony_ci writel(0, msp->registers + MSP_RCF); 60862306a36Sopenharmony_ci writel(0, msp->registers + MSP_DMACR); 60962306a36Sopenharmony_ci writel(0, msp->registers + MSP_SRG); 61062306a36Sopenharmony_ci writel(0, msp->registers + MSP_MCR); 61162306a36Sopenharmony_ci writel(0, msp->registers + MSP_RCM); 61262306a36Sopenharmony_ci writel(0, msp->registers + MSP_RCV); 61362306a36Sopenharmony_ci writel(0, msp->registers + MSP_TCE0); 61462306a36Sopenharmony_ci writel(0, msp->registers + MSP_TCE1); 61562306a36Sopenharmony_ci writel(0, msp->registers + MSP_TCE2); 61662306a36Sopenharmony_ci writel(0, msp->registers + MSP_TCE3); 61762306a36Sopenharmony_ci writel(0, msp->registers + MSP_RCE0); 61862306a36Sopenharmony_ci writel(0, msp->registers + MSP_RCE1); 61962306a36Sopenharmony_ci writel(0, msp->registers + MSP_RCE2); 62062306a36Sopenharmony_ci writel(0, msp->registers + MSP_RCE3); 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci return status; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ciint ux500_msp_i2s_init_msp(struct platform_device *pdev, 62862306a36Sopenharmony_ci struct ux500_msp **msp_p) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci struct resource *res = NULL; 63162306a36Sopenharmony_ci struct ux500_msp *msp; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci *msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL); 63462306a36Sopenharmony_ci msp = *msp_p; 63562306a36Sopenharmony_ci if (!msp) 63662306a36Sopenharmony_ci return -ENOMEM; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci msp->dev = &pdev->dev; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 64162306a36Sopenharmony_ci if (res == NULL) { 64262306a36Sopenharmony_ci dev_err(&pdev->dev, "%s: ERROR: Unable to get resource!\n", 64362306a36Sopenharmony_ci __func__); 64462306a36Sopenharmony_ci return -ENOMEM; 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci msp->tx_rx_addr = res->start + MSP_DR; 64862306a36Sopenharmony_ci msp->registers = devm_ioremap(&pdev->dev, res->start, 64962306a36Sopenharmony_ci resource_size(res)); 65062306a36Sopenharmony_ci if (msp->registers == NULL) { 65162306a36Sopenharmony_ci dev_err(&pdev->dev, "%s: ERROR: ioremap failed!\n", __func__); 65262306a36Sopenharmony_ci return -ENOMEM; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci msp->msp_state = MSP_STATE_IDLE; 65662306a36Sopenharmony_ci msp->loopback_enable = 0; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci return 0; 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_civoid ux500_msp_i2s_cleanup_msp(struct platform_device *pdev, 66262306a36Sopenharmony_ci struct ux500_msp *msp) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci dev_dbg(msp->dev, "%s: Enter (id = %d).\n", __func__, msp->id); 66562306a36Sopenharmony_ci} 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 668