1 /* 2 * rt5677-spi.c -- RT5677 ALSA SoC audio codec driver 3 * 4 * Copyright 2013 Realtek Semiconductor Corp. 5 * Author: Oder Chiou <oder_chiou@realtek.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 12 #include <linux/module.h> 13 #include <linux/input.h> 14 #include <linux/spi/spi.h> 15 #include <linux/device.h> 16 #include <linux/init.h> 17 #include <linux/delay.h> 18 #include <linux/interrupt.h> 19 #include <linux/irq.h> 20 #include <linux/slab.h> 21 #include <linux/gpio.h> 22 #include <linux/sched.h> 23 #include <linux/kthread.h> 24 #include <linux/uaccess.h> 25 #include <linux/miscdevice.h> 26 #include <linux/regulator/consumer.h> 27 #include <linux/pm_qos.h> 28 #include <linux/sysfs.h> 29 #include <linux/clk.h> 30 #include <linux/firmware.h> 31 32 #include "rt5677-spi.h" 33 34 static struct spi_device *g_spi; 35 36 /** 37 * rt5677_spi_write - Write data to SPI. 38 * @txbuf: Data Buffer for writing. 39 * @len: Data length. 40 * 41 * 42 * Returns true for success. 43 */ 44 int rt5677_spi_write(u8 *txbuf, size_t len) 45 { 46 int status; 47 48 status = spi_write(g_spi, txbuf, len); 49 50 if (status) 51 dev_err(&g_spi->dev, "rt5677_spi_write error %d\n", status); 52 53 return status; 54 } 55 EXPORT_SYMBOL_GPL(rt5677_spi_write); 56 57 /** 58 * rt5677_spi_burst_write - Write data to SPI by rt5677 dsp memory address. 59 * @addr: Start address. 60 * @txbuf: Data Buffer for writng. 61 * @len: Data length, it must be a multiple of 8. 62 * 63 * 64 * Returns true for success. 65 */ 66 int rt5677_spi_burst_write(u32 addr, const struct firmware *fw) 67 { 68 u8 spi_cmd = RT5677_SPI_CMD_BURST_WRITE; 69 u8 *write_buf; 70 unsigned int i, end, offset = 0; 71 72 write_buf = kmalloc(RT5677_SPI_BUF_LEN + 6, GFP_KERNEL); 73 74 if (write_buf == NULL) 75 return -ENOMEM; 76 77 while (offset < fw->size) { 78 if (offset + RT5677_SPI_BUF_LEN <= fw->size) 79 end = RT5677_SPI_BUF_LEN; 80 else 81 end = fw->size % RT5677_SPI_BUF_LEN; 82 83 write_buf[0] = spi_cmd; 84 write_buf[1] = ((addr + offset) & 0xff000000) >> 24; 85 write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16; 86 write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8; 87 write_buf[4] = ((addr + offset) & 0x000000ff) >> 0; 88 89 for (i = 0; i < end; i += 8) { 90 write_buf[i + 12] = fw->data[offset + i + 0]; 91 write_buf[i + 11] = fw->data[offset + i + 1]; 92 write_buf[i + 10] = fw->data[offset + i + 2]; 93 write_buf[i + 9] = fw->data[offset + i + 3]; 94 write_buf[i + 8] = fw->data[offset + i + 4]; 95 write_buf[i + 7] = fw->data[offset + i + 5]; 96 write_buf[i + 6] = fw->data[offset + i + 6]; 97 write_buf[i + 5] = fw->data[offset + i + 7]; 98 } 99 100 write_buf[end + 5] = spi_cmd; 101 102 rt5677_spi_write(write_buf, end + 6); 103 104 offset += RT5677_SPI_BUF_LEN; 105 } 106 107 kfree(write_buf); 108 109 return 0; 110 } 111 EXPORT_SYMBOL_GPL(rt5677_spi_burst_write); 112 113 static int rt5677_spi_probe(struct spi_device *spi) 114 { 115 g_spi = spi; 116 return 0; 117 } 118 119 static struct spi_driver rt5677_spi_driver = { 120 .driver = { 121 .name = "rt5677", 122 .owner = THIS_MODULE, 123 }, 124 .probe = rt5677_spi_probe, 125 }; 126 module_spi_driver(rt5677_spi_driver); 127 128 MODULE_DESCRIPTION("ASoC RT5677 SPI driver"); 129 MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>"); 130 MODULE_LICENSE("GPL v2"); 131