Loading sound/soc/codecs/rt5677-spi.c +173 −60 Original line number Diff line number Diff line Loading @@ -31,84 +31,197 @@ #include "rt5677-spi.h" #define RT5677_SPI_BURST_LEN 240 #define RT5677_SPI_HEADER 5 #define RT5677_SPI_FREQ 6000000 /* The AddressPhase and DataPhase of SPI commands are MSB first on the wire. * DataPhase word size of 16-bit commands is 2 bytes. * DataPhase word size of 32-bit commands is 4 bytes. * DataPhase word size of burst commands is 8 bytes. * The DSP CPU is little-endian. */ #define RT5677_SPI_WRITE_BURST 0x5 #define RT5677_SPI_READ_BURST 0x4 #define RT5677_SPI_WRITE_32 0x3 #define RT5677_SPI_READ_32 0x2 #define RT5677_SPI_WRITE_16 0x1 #define RT5677_SPI_READ_16 0x0 static struct spi_device *g_spi; static DEFINE_MUTEX(spi_mutex); /** * rt5677_spi_write - Write data to SPI. * @txbuf: Data Buffer for writing. * @len: Data length. /* Select a suitable transfer command for the next transfer to ensure * the transfer address is always naturally aligned while minimizing * the total number of transfers required. * * 3 transfer commands are available: * RT5677_SPI_READ/WRITE_16: Transfer 2 bytes * RT5677_SPI_READ/WRITE_32: Transfer 4 bytes * RT5677_SPI_READ/WRITE_BURST: Transfer any multiples of 8 bytes * * For example, reading 260 bytes at 0x60030002 uses the following commands: * 0x60030002 RT5677_SPI_READ_16 2 bytes * 0x60030004 RT5677_SPI_READ_32 4 bytes * 0x60030008 RT5677_SPI_READ_BURST 240 bytes * 0x600300F8 RT5677_SPI_READ_BURST 8 bytes * 0x60030100 RT5677_SPI_READ_32 4 bytes * 0x60030104 RT5677_SPI_READ_16 2 bytes * * Input: * @read: true for read commands; false for write commands * @align: alignment of the next transfer address * @remain: number of bytes remaining to transfer * * Returns true for success. * Output: * @len: number of bytes to transfer with the selected command * Returns the selected command */ int rt5677_spi_write(u8 *txbuf, size_t len) static u8 rt5677_spi_select_cmd(bool read, u32 align, u32 remain, u32 *len) { int status; u8 cmd; if (align == 2 || align == 6 || remain == 2) { cmd = RT5677_SPI_READ_16; *len = 2; } else if (align == 4 || remain <= 6) { cmd = RT5677_SPI_READ_32; *len = 4; } else { cmd = RT5677_SPI_READ_BURST; *len = min_t(u32, remain & ~7, RT5677_SPI_BURST_LEN); } return read ? cmd : cmd + 1; } status = spi_write(g_spi, txbuf, len); /* Copy dstlen bytes from src to dst, while reversing byte order for each word. * If srclen < dstlen, zeros are padded. */ static void rt5677_spi_reverse(u8 *dst, u32 dstlen, const u8 *src, u32 srclen) { u32 w, i, si; u32 word_size = min_t(u32, dstlen, 8); for (w = 0; w < dstlen; w += word_size) { for (i = 0; i < word_size; i++) { si = w + word_size - i - 1; dst[w + i] = si < srclen ? src[si] : 0; } } } if (status) dev_err(&g_spi->dev, "rt5677_spi_write error %d\n", status); /* Read DSP address space using SPI. addr and len have to be 2-byte aligned. */ int rt5677_spi_read(u32 addr, void *rxbuf, size_t len) { u32 offset; int status = 0; struct spi_transfer t[2]; struct spi_message m; /* +4 bytes is for the DummyPhase following the AddressPhase */ u8 header[RT5677_SPI_HEADER + 4]; u8 body[RT5677_SPI_BURST_LEN]; u8 spi_cmd; u8 *cb = rxbuf; if (!g_spi) return -ENODEV; if ((addr & 1) || (len & 1)) { dev_err(&g_spi->dev, "Bad read align 0x%x(%zu)\n", addr, len); return -EACCES; } memset(t, 0, sizeof(t)); t[0].tx_buf = header; t[0].len = sizeof(header); t[0].speed_hz = RT5677_SPI_FREQ; t[1].rx_buf = body; t[1].speed_hz = RT5677_SPI_FREQ; spi_message_init_with_transfers(&m, t, ARRAY_SIZE(t)); for (offset = 0; offset < len; offset += t[1].len) { spi_cmd = rt5677_spi_select_cmd(true, (addr + offset) & 7, len - offset, &t[1].len); /* Construct SPI message header */ header[0] = spi_cmd; header[1] = ((addr + offset) & 0xff000000) >> 24; header[2] = ((addr + offset) & 0x00ff0000) >> 16; header[3] = ((addr + offset) & 0x0000ff00) >> 8; header[4] = ((addr + offset) & 0x000000ff) >> 0; mutex_lock(&spi_mutex); status |= spi_sync(g_spi, &m); mutex_unlock(&spi_mutex); /* Copy data back to caller buffer */ rt5677_spi_reverse(cb + offset, t[1].len, body, t[1].len); } return status; } EXPORT_SYMBOL_GPL(rt5677_spi_write); EXPORT_SYMBOL_GPL(rt5677_spi_read); /** * rt5677_spi_burst_write - Write data to SPI by rt5677 dsp memory address. * @addr: Start address. * @txbuf: Data Buffer for writng. * @len: Data length, it must be a multiple of 8. * * * Returns true for success. /* Write DSP address space using SPI. addr has to be 2-byte aligned. * If len is not 2-byte aligned, an extra byte of zero is written at the end * as padding. */ int rt5677_spi_burst_write(u32 addr, const struct firmware *fw) int rt5677_spi_write(u32 addr, const void *txbuf, size_t len) { u8 spi_cmd = RT5677_SPI_CMD_BURST_WRITE; u8 *write_buf; unsigned int i, end, offset = 0; write_buf = kmalloc(RT5677_SPI_BUF_LEN + 6, GFP_KERNEL); if (write_buf == NULL) return -ENOMEM; while (offset < fw->size) { if (offset + RT5677_SPI_BUF_LEN <= fw->size) end = RT5677_SPI_BUF_LEN; else end = fw->size % RT5677_SPI_BUF_LEN; write_buf[0] = spi_cmd; write_buf[1] = ((addr + offset) & 0xff000000) >> 24; write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16; write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8; write_buf[4] = ((addr + offset) & 0x000000ff) >> 0; for (i = 0; i < end; i += 8) { write_buf[i + 12] = fw->data[offset + i + 0]; write_buf[i + 11] = fw->data[offset + i + 1]; write_buf[i + 10] = fw->data[offset + i + 2]; write_buf[i + 9] = fw->data[offset + i + 3]; write_buf[i + 8] = fw->data[offset + i + 4]; write_buf[i + 7] = fw->data[offset + i + 5]; write_buf[i + 6] = fw->data[offset + i + 6]; write_buf[i + 5] = fw->data[offset + i + 7]; u32 offset, len_with_pad = len; int status = 0; struct spi_transfer t; struct spi_message m; /* +1 byte is for the DummyPhase following the DataPhase */ u8 buf[RT5677_SPI_HEADER + RT5677_SPI_BURST_LEN + 1]; u8 *body = buf + RT5677_SPI_HEADER; u8 spi_cmd; const u8 *cb = txbuf; if (!g_spi) return -ENODEV; if (addr & 1) { dev_err(&g_spi->dev, "Bad write align 0x%x(%zu)\n", addr, len); return -EACCES; } write_buf[end + 5] = spi_cmd; rt5677_spi_write(write_buf, end + 6); offset += RT5677_SPI_BUF_LEN; if (len & 1) len_with_pad = len + 1; memset(&t, 0, sizeof(t)); t.tx_buf = buf; t.speed_hz = RT5677_SPI_FREQ; spi_message_init_with_transfers(&m, &t, 1); for (offset = 0; offset < len_with_pad;) { spi_cmd = rt5677_spi_select_cmd(false, (addr + offset) & 7, len_with_pad - offset, &t.len); /* Construct SPI message header */ buf[0] = spi_cmd; buf[1] = ((addr + offset) & 0xff000000) >> 24; buf[2] = ((addr + offset) & 0x00ff0000) >> 16; buf[3] = ((addr + offset) & 0x0000ff00) >> 8; buf[4] = ((addr + offset) & 0x000000ff) >> 0; /* Fetch data from caller buffer */ rt5677_spi_reverse(body, t.len, cb + offset, len - offset); offset += t.len; t.len += RT5677_SPI_HEADER + 1; mutex_lock(&spi_mutex); status |= spi_sync(g_spi, &m); mutex_unlock(&spi_mutex); } return status; } EXPORT_SYMBOL_GPL(rt5677_spi_write); kfree(write_buf); return 0; int rt5677_spi_write_firmware(u32 addr, const struct firmware *fw) { return rt5677_spi_write(addr, fw->data, fw->size); } EXPORT_SYMBOL_GPL(rt5677_spi_burst_write); EXPORT_SYMBOL_GPL(rt5677_spi_write_firmware); static int rt5677_spi_probe(struct spi_device *spi) { Loading sound/soc/codecs/rt5677-spi.h +3 −5 Original line number Diff line number Diff line Loading @@ -12,10 +12,8 @@ #ifndef __RT5677_SPI_H__ #define __RT5677_SPI_H__ #define RT5677_SPI_BUF_LEN 240 #define RT5677_SPI_CMD_BURST_WRITE 0x05 int rt5677_spi_write(u8 *txbuf, size_t len); int rt5677_spi_burst_write(u32 addr, const struct firmware *fw); int rt5677_spi_read(u32 addr, void *rxbuf, size_t len); int rt5677_spi_write(u32 addr, const void *txbuf, size_t len); int rt5677_spi_write_firmware(u32 addr, const struct firmware *fw); #endif /* __RT5677_SPI_H__ */ sound/soc/codecs/rt5677.c +52 −90 Original line number Diff line number Diff line Loading @@ -15,13 +15,12 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> #include <linux/of_gpio.h> #include <linux/regmap.h> #include <linux/i2c.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/firmware.h> #include <linux/gpio.h> #include <linux/property.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> Loading Loading @@ -746,14 +745,14 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on) ret = request_firmware(&rt5677->fw1, RT5677_FIRMWARE1, codec->dev); if (ret == 0) { rt5677_spi_burst_write(0x50000000, rt5677->fw1); rt5677_spi_write_firmware(0x50000000, rt5677->fw1); release_firmware(rt5677->fw1); } ret = request_firmware(&rt5677->fw2, RT5677_FIRMWARE2, codec->dev); if (ret == 0) { rt5677_spi_burst_write(0x60000000, rt5677->fw2); rt5677_spi_write_firmware(0x60000000, rt5677->fw2); release_firmware(rt5677->fw2); } Loading Loading @@ -4767,10 +4766,8 @@ static int rt5677_remove(struct snd_soc_codec *codec) struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); if (gpio_is_valid(rt5677->pow_ldo2)) gpio_set_value_cansleep(rt5677->pow_ldo2, 0); if (gpio_is_valid(rt5677->reset_pin)) gpio_set_value_cansleep(rt5677->reset_pin, 0); gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); gpiod_set_value_cansleep(rt5677->reset_pin, 0); return 0; } Loading @@ -4784,10 +4781,8 @@ static int rt5677_suspend(struct snd_soc_codec *codec) regcache_cache_only(rt5677->regmap, true); regcache_mark_dirty(rt5677->regmap); if (gpio_is_valid(rt5677->pow_ldo2)) gpio_set_value_cansleep(rt5677->pow_ldo2, 0); if (gpio_is_valid(rt5677->reset_pin)) gpio_set_value_cansleep(rt5677->reset_pin, 0); gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); gpiod_set_value_cansleep(rt5677->reset_pin, 0); } return 0; Loading @@ -4798,12 +4793,9 @@ static int rt5677_resume(struct snd_soc_codec *codec) struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); if (!rt5677->dsp_vad_en) { if (gpio_is_valid(rt5677->pow_ldo2)) gpio_set_value_cansleep(rt5677->pow_ldo2, 1); if (gpio_is_valid(rt5677->reset_pin)) gpio_set_value_cansleep(rt5677->reset_pin, 1); if (gpio_is_valid(rt5677->pow_ldo2) || gpio_is_valid(rt5677->reset_pin)) gpiod_set_value_cansleep(rt5677->pow_ldo2, 1); gpiod_set_value_cansleep(rt5677->reset_pin, 1); if (rt5677->pow_ldo2 || rt5677->reset_pin) msleep(10); regcache_cache_only(rt5677->regmap, false); Loading Loading @@ -5027,45 +5019,29 @@ static const struct i2c_device_id rt5677_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id); static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np) static void rt5677_read_device_properties(struct rt5677_priv *rt5677, struct device *dev) { rt5677->pdata.in1_diff = of_property_read_bool(np, rt5677->pdata.in1_diff = device_property_read_bool(dev, "realtek,in1-differential"); rt5677->pdata.in2_diff = of_property_read_bool(np, rt5677->pdata.in2_diff = device_property_read_bool(dev, "realtek,in2-differential"); rt5677->pdata.lout1_diff = of_property_read_bool(np, rt5677->pdata.lout1_diff = device_property_read_bool(dev, "realtek,lout1-differential"); rt5677->pdata.lout2_diff = of_property_read_bool(np, rt5677->pdata.lout2_diff = device_property_read_bool(dev, "realtek,lout2-differential"); rt5677->pdata.lout3_diff = of_property_read_bool(np, rt5677->pdata.lout3_diff = device_property_read_bool(dev, "realtek,lout3-differential"); rt5677->pow_ldo2 = of_get_named_gpio(np, "realtek,pow-ldo2-gpio", 0); rt5677->reset_pin = of_get_named_gpio(np, "realtek,reset-gpio", 0); /* * POW_LDO2 is optional (it may be statically tied on the board). * -ENOENT means that the property doesn't exist, i.e. there is no * GPIO, so is not an error. Any other error code means the property * exists, but could not be parsed. */ if (!gpio_is_valid(rt5677->pow_ldo2) && (rt5677->pow_ldo2 != -ENOENT)) return rt5677->pow_ldo2; if (!gpio_is_valid(rt5677->reset_pin) && (rt5677->reset_pin != -ENOENT)) return rt5677->reset_pin; of_property_read_u8_array(np, "realtek,gpio-config", device_property_read_u8_array(dev, "realtek,gpio-config", rt5677->pdata.gpio_config, RT5677_GPIO_NUM); of_property_read_u32(np, "realtek,jd1-gpio", &rt5677->pdata.jd1_gpio); of_property_read_u32(np, "realtek,jd2-gpio", &rt5677->pdata.jd2_gpio); of_property_read_u32(np, "realtek,jd3-gpio", &rt5677->pdata.jd3_gpio); return 0; device_property_read_u32(dev, "realtek,jd1-gpio", &rt5677->pdata.jd1_gpio); device_property_read_u32(dev, "realtek,jd2-gpio", &rt5677->pdata.jd2_gpio); device_property_read_u32(dev, "realtek,jd3-gpio", &rt5677->pdata.jd3_gpio); } static struct regmap_irq rt5677_irqs[] = { Loading Loading @@ -5148,43 +5124,29 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, if (pdata) rt5677->pdata = *pdata; else rt5677_read_device_properties(rt5677, &i2c->dev); if (i2c->dev.of_node) { ret = rt5677_parse_dt(rt5677, i2c->dev.of_node); if (ret) { dev_err(&i2c->dev, "Failed to parse device tree: %d\n", ret); return ret; } } else { rt5677->pow_ldo2 = -EINVAL; rt5677->reset_pin = -EINVAL; } if (gpio_is_valid(rt5677->pow_ldo2)) { ret = devm_gpio_request_one(&i2c->dev, rt5677->pow_ldo2, GPIOF_OUT_INIT_HIGH, "RT5677 POW_LDO2"); if (ret < 0) { dev_err(&i2c->dev, "Failed to request POW_LDO2 %d: %d\n", rt5677->pow_ldo2, ret); /* pow-ldo2 and reset are optional. The codec pins may be statically * connected on the board without gpios. If the gpio device property * isn't specified, devm_gpiod_get_optional returns NULL. */ rt5677->pow_ldo2 = devm_gpiod_get_optional(&i2c->dev, "realtek,pow-ldo2", GPIOD_OUT_HIGH); if (IS_ERR(rt5677->pow_ldo2)) { ret = PTR_ERR(rt5677->pow_ldo2); dev_err(&i2c->dev, "Failed to request POW_LDO2: %d\n", ret); return ret; } } if (gpio_is_valid(rt5677->reset_pin)) { ret = devm_gpio_request_one(&i2c->dev, rt5677->reset_pin, GPIOF_OUT_INIT_HIGH, "RT5677 RESET"); if (ret < 0) { dev_err(&i2c->dev, "Failed to request RESET %d: %d\n", rt5677->reset_pin, ret); rt5677->reset_pin = devm_gpiod_get_optional(&i2c->dev, "realtek,reset", GPIOD_OUT_HIGH); if (IS_ERR(rt5677->reset_pin)) { ret = PTR_ERR(rt5677->reset_pin); dev_err(&i2c->dev, "Failed to request RESET: %d\n", ret); return ret; } } if (gpio_is_valid(rt5677->pow_ldo2) || gpio_is_valid(rt5677->reset_pin)) { if (rt5677->pow_ldo2 || rt5677->reset_pin) { /* Wait a while until I2C bus becomes available. The datasheet * does not specify the exact we should wait but startup * sequence mentiones at least a few milliseconds. Loading Loading @@ -5212,7 +5174,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, regmap_read(rt5677->regmap, RT5677_VENDOR_ID2, &val); if (val != RT5677_DEVICE_ID) { dev_err(&i2c->dev, "Device with ID register %x is not rt5677\n", val); "Device with ID register %#x is not rt5677\n", val); return -ENODEV; } Loading sound/soc/codecs/rt5677.h +3 −2 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ #include <sound/rt5677.h> #include <linux/gpio/driver.h> #include <linux/gpio/consumer.h> /* Info */ #define RT5677_RESET 0x00 Loading Loading @@ -1775,8 +1776,8 @@ struct rt5677_priv { int pll_src; int pll_in; int pll_out; int pow_ldo2; /* POW_LDO2 pin */ int reset_pin; /* RESET pin */ struct gpio_desc *pow_ldo2; /* POW_LDO2 pin */ struct gpio_desc *reset_pin; /* RESET pin */ enum rt5677_type type; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio_chip; Loading sound/soc/codecs/sirf-audio-codec.c +2 −2 Original line number Diff line number Diff line Loading @@ -370,11 +370,11 @@ static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream, return 0; } struct snd_soc_dai_ops sirf_audio_codec_dai_ops = { static const struct snd_soc_dai_ops sirf_audio_codec_dai_ops = { .trigger = sirf_audio_codec_trigger, }; struct snd_soc_dai_driver sirf_audio_codec_dai = { static struct snd_soc_dai_driver sirf_audio_codec_dai = { .name = "sirf-audio-codec", .playback = { .stream_name = "Playback", Loading Loading
sound/soc/codecs/rt5677-spi.c +173 −60 Original line number Diff line number Diff line Loading @@ -31,84 +31,197 @@ #include "rt5677-spi.h" #define RT5677_SPI_BURST_LEN 240 #define RT5677_SPI_HEADER 5 #define RT5677_SPI_FREQ 6000000 /* The AddressPhase and DataPhase of SPI commands are MSB first on the wire. * DataPhase word size of 16-bit commands is 2 bytes. * DataPhase word size of 32-bit commands is 4 bytes. * DataPhase word size of burst commands is 8 bytes. * The DSP CPU is little-endian. */ #define RT5677_SPI_WRITE_BURST 0x5 #define RT5677_SPI_READ_BURST 0x4 #define RT5677_SPI_WRITE_32 0x3 #define RT5677_SPI_READ_32 0x2 #define RT5677_SPI_WRITE_16 0x1 #define RT5677_SPI_READ_16 0x0 static struct spi_device *g_spi; static DEFINE_MUTEX(spi_mutex); /** * rt5677_spi_write - Write data to SPI. * @txbuf: Data Buffer for writing. * @len: Data length. /* Select a suitable transfer command for the next transfer to ensure * the transfer address is always naturally aligned while minimizing * the total number of transfers required. * * 3 transfer commands are available: * RT5677_SPI_READ/WRITE_16: Transfer 2 bytes * RT5677_SPI_READ/WRITE_32: Transfer 4 bytes * RT5677_SPI_READ/WRITE_BURST: Transfer any multiples of 8 bytes * * For example, reading 260 bytes at 0x60030002 uses the following commands: * 0x60030002 RT5677_SPI_READ_16 2 bytes * 0x60030004 RT5677_SPI_READ_32 4 bytes * 0x60030008 RT5677_SPI_READ_BURST 240 bytes * 0x600300F8 RT5677_SPI_READ_BURST 8 bytes * 0x60030100 RT5677_SPI_READ_32 4 bytes * 0x60030104 RT5677_SPI_READ_16 2 bytes * * Input: * @read: true for read commands; false for write commands * @align: alignment of the next transfer address * @remain: number of bytes remaining to transfer * * Returns true for success. * Output: * @len: number of bytes to transfer with the selected command * Returns the selected command */ int rt5677_spi_write(u8 *txbuf, size_t len) static u8 rt5677_spi_select_cmd(bool read, u32 align, u32 remain, u32 *len) { int status; u8 cmd; if (align == 2 || align == 6 || remain == 2) { cmd = RT5677_SPI_READ_16; *len = 2; } else if (align == 4 || remain <= 6) { cmd = RT5677_SPI_READ_32; *len = 4; } else { cmd = RT5677_SPI_READ_BURST; *len = min_t(u32, remain & ~7, RT5677_SPI_BURST_LEN); } return read ? cmd : cmd + 1; } status = spi_write(g_spi, txbuf, len); /* Copy dstlen bytes from src to dst, while reversing byte order for each word. * If srclen < dstlen, zeros are padded. */ static void rt5677_spi_reverse(u8 *dst, u32 dstlen, const u8 *src, u32 srclen) { u32 w, i, si; u32 word_size = min_t(u32, dstlen, 8); for (w = 0; w < dstlen; w += word_size) { for (i = 0; i < word_size; i++) { si = w + word_size - i - 1; dst[w + i] = si < srclen ? src[si] : 0; } } } if (status) dev_err(&g_spi->dev, "rt5677_spi_write error %d\n", status); /* Read DSP address space using SPI. addr and len have to be 2-byte aligned. */ int rt5677_spi_read(u32 addr, void *rxbuf, size_t len) { u32 offset; int status = 0; struct spi_transfer t[2]; struct spi_message m; /* +4 bytes is for the DummyPhase following the AddressPhase */ u8 header[RT5677_SPI_HEADER + 4]; u8 body[RT5677_SPI_BURST_LEN]; u8 spi_cmd; u8 *cb = rxbuf; if (!g_spi) return -ENODEV; if ((addr & 1) || (len & 1)) { dev_err(&g_spi->dev, "Bad read align 0x%x(%zu)\n", addr, len); return -EACCES; } memset(t, 0, sizeof(t)); t[0].tx_buf = header; t[0].len = sizeof(header); t[0].speed_hz = RT5677_SPI_FREQ; t[1].rx_buf = body; t[1].speed_hz = RT5677_SPI_FREQ; spi_message_init_with_transfers(&m, t, ARRAY_SIZE(t)); for (offset = 0; offset < len; offset += t[1].len) { spi_cmd = rt5677_spi_select_cmd(true, (addr + offset) & 7, len - offset, &t[1].len); /* Construct SPI message header */ header[0] = spi_cmd; header[1] = ((addr + offset) & 0xff000000) >> 24; header[2] = ((addr + offset) & 0x00ff0000) >> 16; header[3] = ((addr + offset) & 0x0000ff00) >> 8; header[4] = ((addr + offset) & 0x000000ff) >> 0; mutex_lock(&spi_mutex); status |= spi_sync(g_spi, &m); mutex_unlock(&spi_mutex); /* Copy data back to caller buffer */ rt5677_spi_reverse(cb + offset, t[1].len, body, t[1].len); } return status; } EXPORT_SYMBOL_GPL(rt5677_spi_write); EXPORT_SYMBOL_GPL(rt5677_spi_read); /** * rt5677_spi_burst_write - Write data to SPI by rt5677 dsp memory address. * @addr: Start address. * @txbuf: Data Buffer for writng. * @len: Data length, it must be a multiple of 8. * * * Returns true for success. /* Write DSP address space using SPI. addr has to be 2-byte aligned. * If len is not 2-byte aligned, an extra byte of zero is written at the end * as padding. */ int rt5677_spi_burst_write(u32 addr, const struct firmware *fw) int rt5677_spi_write(u32 addr, const void *txbuf, size_t len) { u8 spi_cmd = RT5677_SPI_CMD_BURST_WRITE; u8 *write_buf; unsigned int i, end, offset = 0; write_buf = kmalloc(RT5677_SPI_BUF_LEN + 6, GFP_KERNEL); if (write_buf == NULL) return -ENOMEM; while (offset < fw->size) { if (offset + RT5677_SPI_BUF_LEN <= fw->size) end = RT5677_SPI_BUF_LEN; else end = fw->size % RT5677_SPI_BUF_LEN; write_buf[0] = spi_cmd; write_buf[1] = ((addr + offset) & 0xff000000) >> 24; write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16; write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8; write_buf[4] = ((addr + offset) & 0x000000ff) >> 0; for (i = 0; i < end; i += 8) { write_buf[i + 12] = fw->data[offset + i + 0]; write_buf[i + 11] = fw->data[offset + i + 1]; write_buf[i + 10] = fw->data[offset + i + 2]; write_buf[i + 9] = fw->data[offset + i + 3]; write_buf[i + 8] = fw->data[offset + i + 4]; write_buf[i + 7] = fw->data[offset + i + 5]; write_buf[i + 6] = fw->data[offset + i + 6]; write_buf[i + 5] = fw->data[offset + i + 7]; u32 offset, len_with_pad = len; int status = 0; struct spi_transfer t; struct spi_message m; /* +1 byte is for the DummyPhase following the DataPhase */ u8 buf[RT5677_SPI_HEADER + RT5677_SPI_BURST_LEN + 1]; u8 *body = buf + RT5677_SPI_HEADER; u8 spi_cmd; const u8 *cb = txbuf; if (!g_spi) return -ENODEV; if (addr & 1) { dev_err(&g_spi->dev, "Bad write align 0x%x(%zu)\n", addr, len); return -EACCES; } write_buf[end + 5] = spi_cmd; rt5677_spi_write(write_buf, end + 6); offset += RT5677_SPI_BUF_LEN; if (len & 1) len_with_pad = len + 1; memset(&t, 0, sizeof(t)); t.tx_buf = buf; t.speed_hz = RT5677_SPI_FREQ; spi_message_init_with_transfers(&m, &t, 1); for (offset = 0; offset < len_with_pad;) { spi_cmd = rt5677_spi_select_cmd(false, (addr + offset) & 7, len_with_pad - offset, &t.len); /* Construct SPI message header */ buf[0] = spi_cmd; buf[1] = ((addr + offset) & 0xff000000) >> 24; buf[2] = ((addr + offset) & 0x00ff0000) >> 16; buf[3] = ((addr + offset) & 0x0000ff00) >> 8; buf[4] = ((addr + offset) & 0x000000ff) >> 0; /* Fetch data from caller buffer */ rt5677_spi_reverse(body, t.len, cb + offset, len - offset); offset += t.len; t.len += RT5677_SPI_HEADER + 1; mutex_lock(&spi_mutex); status |= spi_sync(g_spi, &m); mutex_unlock(&spi_mutex); } return status; } EXPORT_SYMBOL_GPL(rt5677_spi_write); kfree(write_buf); return 0; int rt5677_spi_write_firmware(u32 addr, const struct firmware *fw) { return rt5677_spi_write(addr, fw->data, fw->size); } EXPORT_SYMBOL_GPL(rt5677_spi_burst_write); EXPORT_SYMBOL_GPL(rt5677_spi_write_firmware); static int rt5677_spi_probe(struct spi_device *spi) { Loading
sound/soc/codecs/rt5677-spi.h +3 −5 Original line number Diff line number Diff line Loading @@ -12,10 +12,8 @@ #ifndef __RT5677_SPI_H__ #define __RT5677_SPI_H__ #define RT5677_SPI_BUF_LEN 240 #define RT5677_SPI_CMD_BURST_WRITE 0x05 int rt5677_spi_write(u8 *txbuf, size_t len); int rt5677_spi_burst_write(u32 addr, const struct firmware *fw); int rt5677_spi_read(u32 addr, void *rxbuf, size_t len); int rt5677_spi_write(u32 addr, const void *txbuf, size_t len); int rt5677_spi_write_firmware(u32 addr, const struct firmware *fw); #endif /* __RT5677_SPI_H__ */
sound/soc/codecs/rt5677.c +52 −90 Original line number Diff line number Diff line Loading @@ -15,13 +15,12 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> #include <linux/of_gpio.h> #include <linux/regmap.h> #include <linux/i2c.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/firmware.h> #include <linux/gpio.h> #include <linux/property.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> Loading Loading @@ -746,14 +745,14 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on) ret = request_firmware(&rt5677->fw1, RT5677_FIRMWARE1, codec->dev); if (ret == 0) { rt5677_spi_burst_write(0x50000000, rt5677->fw1); rt5677_spi_write_firmware(0x50000000, rt5677->fw1); release_firmware(rt5677->fw1); } ret = request_firmware(&rt5677->fw2, RT5677_FIRMWARE2, codec->dev); if (ret == 0) { rt5677_spi_burst_write(0x60000000, rt5677->fw2); rt5677_spi_write_firmware(0x60000000, rt5677->fw2); release_firmware(rt5677->fw2); } Loading Loading @@ -4767,10 +4766,8 @@ static int rt5677_remove(struct snd_soc_codec *codec) struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); if (gpio_is_valid(rt5677->pow_ldo2)) gpio_set_value_cansleep(rt5677->pow_ldo2, 0); if (gpio_is_valid(rt5677->reset_pin)) gpio_set_value_cansleep(rt5677->reset_pin, 0); gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); gpiod_set_value_cansleep(rt5677->reset_pin, 0); return 0; } Loading @@ -4784,10 +4781,8 @@ static int rt5677_suspend(struct snd_soc_codec *codec) regcache_cache_only(rt5677->regmap, true); regcache_mark_dirty(rt5677->regmap); if (gpio_is_valid(rt5677->pow_ldo2)) gpio_set_value_cansleep(rt5677->pow_ldo2, 0); if (gpio_is_valid(rt5677->reset_pin)) gpio_set_value_cansleep(rt5677->reset_pin, 0); gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); gpiod_set_value_cansleep(rt5677->reset_pin, 0); } return 0; Loading @@ -4798,12 +4793,9 @@ static int rt5677_resume(struct snd_soc_codec *codec) struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); if (!rt5677->dsp_vad_en) { if (gpio_is_valid(rt5677->pow_ldo2)) gpio_set_value_cansleep(rt5677->pow_ldo2, 1); if (gpio_is_valid(rt5677->reset_pin)) gpio_set_value_cansleep(rt5677->reset_pin, 1); if (gpio_is_valid(rt5677->pow_ldo2) || gpio_is_valid(rt5677->reset_pin)) gpiod_set_value_cansleep(rt5677->pow_ldo2, 1); gpiod_set_value_cansleep(rt5677->reset_pin, 1); if (rt5677->pow_ldo2 || rt5677->reset_pin) msleep(10); regcache_cache_only(rt5677->regmap, false); Loading Loading @@ -5027,45 +5019,29 @@ static const struct i2c_device_id rt5677_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id); static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np) static void rt5677_read_device_properties(struct rt5677_priv *rt5677, struct device *dev) { rt5677->pdata.in1_diff = of_property_read_bool(np, rt5677->pdata.in1_diff = device_property_read_bool(dev, "realtek,in1-differential"); rt5677->pdata.in2_diff = of_property_read_bool(np, rt5677->pdata.in2_diff = device_property_read_bool(dev, "realtek,in2-differential"); rt5677->pdata.lout1_diff = of_property_read_bool(np, rt5677->pdata.lout1_diff = device_property_read_bool(dev, "realtek,lout1-differential"); rt5677->pdata.lout2_diff = of_property_read_bool(np, rt5677->pdata.lout2_diff = device_property_read_bool(dev, "realtek,lout2-differential"); rt5677->pdata.lout3_diff = of_property_read_bool(np, rt5677->pdata.lout3_diff = device_property_read_bool(dev, "realtek,lout3-differential"); rt5677->pow_ldo2 = of_get_named_gpio(np, "realtek,pow-ldo2-gpio", 0); rt5677->reset_pin = of_get_named_gpio(np, "realtek,reset-gpio", 0); /* * POW_LDO2 is optional (it may be statically tied on the board). * -ENOENT means that the property doesn't exist, i.e. there is no * GPIO, so is not an error. Any other error code means the property * exists, but could not be parsed. */ if (!gpio_is_valid(rt5677->pow_ldo2) && (rt5677->pow_ldo2 != -ENOENT)) return rt5677->pow_ldo2; if (!gpio_is_valid(rt5677->reset_pin) && (rt5677->reset_pin != -ENOENT)) return rt5677->reset_pin; of_property_read_u8_array(np, "realtek,gpio-config", device_property_read_u8_array(dev, "realtek,gpio-config", rt5677->pdata.gpio_config, RT5677_GPIO_NUM); of_property_read_u32(np, "realtek,jd1-gpio", &rt5677->pdata.jd1_gpio); of_property_read_u32(np, "realtek,jd2-gpio", &rt5677->pdata.jd2_gpio); of_property_read_u32(np, "realtek,jd3-gpio", &rt5677->pdata.jd3_gpio); return 0; device_property_read_u32(dev, "realtek,jd1-gpio", &rt5677->pdata.jd1_gpio); device_property_read_u32(dev, "realtek,jd2-gpio", &rt5677->pdata.jd2_gpio); device_property_read_u32(dev, "realtek,jd3-gpio", &rt5677->pdata.jd3_gpio); } static struct regmap_irq rt5677_irqs[] = { Loading Loading @@ -5148,43 +5124,29 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, if (pdata) rt5677->pdata = *pdata; else rt5677_read_device_properties(rt5677, &i2c->dev); if (i2c->dev.of_node) { ret = rt5677_parse_dt(rt5677, i2c->dev.of_node); if (ret) { dev_err(&i2c->dev, "Failed to parse device tree: %d\n", ret); return ret; } } else { rt5677->pow_ldo2 = -EINVAL; rt5677->reset_pin = -EINVAL; } if (gpio_is_valid(rt5677->pow_ldo2)) { ret = devm_gpio_request_one(&i2c->dev, rt5677->pow_ldo2, GPIOF_OUT_INIT_HIGH, "RT5677 POW_LDO2"); if (ret < 0) { dev_err(&i2c->dev, "Failed to request POW_LDO2 %d: %d\n", rt5677->pow_ldo2, ret); /* pow-ldo2 and reset are optional. The codec pins may be statically * connected on the board without gpios. If the gpio device property * isn't specified, devm_gpiod_get_optional returns NULL. */ rt5677->pow_ldo2 = devm_gpiod_get_optional(&i2c->dev, "realtek,pow-ldo2", GPIOD_OUT_HIGH); if (IS_ERR(rt5677->pow_ldo2)) { ret = PTR_ERR(rt5677->pow_ldo2); dev_err(&i2c->dev, "Failed to request POW_LDO2: %d\n", ret); return ret; } } if (gpio_is_valid(rt5677->reset_pin)) { ret = devm_gpio_request_one(&i2c->dev, rt5677->reset_pin, GPIOF_OUT_INIT_HIGH, "RT5677 RESET"); if (ret < 0) { dev_err(&i2c->dev, "Failed to request RESET %d: %d\n", rt5677->reset_pin, ret); rt5677->reset_pin = devm_gpiod_get_optional(&i2c->dev, "realtek,reset", GPIOD_OUT_HIGH); if (IS_ERR(rt5677->reset_pin)) { ret = PTR_ERR(rt5677->reset_pin); dev_err(&i2c->dev, "Failed to request RESET: %d\n", ret); return ret; } } if (gpio_is_valid(rt5677->pow_ldo2) || gpio_is_valid(rt5677->reset_pin)) { if (rt5677->pow_ldo2 || rt5677->reset_pin) { /* Wait a while until I2C bus becomes available. The datasheet * does not specify the exact we should wait but startup * sequence mentiones at least a few milliseconds. Loading Loading @@ -5212,7 +5174,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, regmap_read(rt5677->regmap, RT5677_VENDOR_ID2, &val); if (val != RT5677_DEVICE_ID) { dev_err(&i2c->dev, "Device with ID register %x is not rt5677\n", val); "Device with ID register %#x is not rt5677\n", val); return -ENODEV; } Loading
sound/soc/codecs/rt5677.h +3 −2 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ #include <sound/rt5677.h> #include <linux/gpio/driver.h> #include <linux/gpio/consumer.h> /* Info */ #define RT5677_RESET 0x00 Loading Loading @@ -1775,8 +1776,8 @@ struct rt5677_priv { int pll_src; int pll_in; int pll_out; int pow_ldo2; /* POW_LDO2 pin */ int reset_pin; /* RESET pin */ struct gpio_desc *pow_ldo2; /* POW_LDO2 pin */ struct gpio_desc *reset_pin; /* RESET pin */ enum rt5677_type type; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio_chip; Loading
sound/soc/codecs/sirf-audio-codec.c +2 −2 Original line number Diff line number Diff line Loading @@ -370,11 +370,11 @@ static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream, return 0; } struct snd_soc_dai_ops sirf_audio_codec_dai_ops = { static const struct snd_soc_dai_ops sirf_audio_codec_dai_ops = { .trigger = sirf_audio_codec_trigger, }; struct snd_soc_dai_driver sirf_audio_codec_dai = { static struct snd_soc_dai_driver sirf_audio_codec_dai = { .name = "sirf-audio-codec", .playback = { .stream_name = "Playback", Loading