From d1adb29d59e4e458859149394efc74a869058963 Mon Sep 17 00:00:00 2001 From: Huibin Hong Date: Wed, 12 Jul 2017 10:27:51 +0800 Subject: [PATCH] spi: rockchip: test: update driver Change-Id: I773cdc245fcdf8eee10dd7983343f206aecb856c Signed-off-by: Huibin Hong --- drivers/spi/spi-rockchip-test.c | 755 ++++++++++++++++++++------------ 1 file changed, 487 insertions(+), 268 deletions(-) diff --git a/drivers/spi/spi-rockchip-test.c b/drivers/spi/spi-rockchip-test.c index 4ac0658e95ae..9b2ac14d33bc 100755 --- a/drivers/spi/spi-rockchip-test.c +++ b/drivers/spi/spi-rockchip-test.c @@ -1,268 +1,487 @@ -/*drivers/serial/spi_test.c -spi test driver - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "spi-rockchip-core.h" - -#define MAX_SPI_DEV_NUM 6 -#define SPI_MAX_SPEED_HZ 12000000 - - -struct spi_test_data { - struct device *dev; - struct spi_device *spi; - char *rx_buf; - int rx_len; - char *tx_buf; - int tx_len; -}; - -static struct spi_test_data *g_spi_test_data[MAX_SPI_DEV_NUM]; - - -static ssize_t spi_test_write(struct file *file, - const char __user *buf, size_t count, loff_t *offset) -{ - u8 nr_buf[8]; - int nr = 0, ret; - int i = 0; - struct spi_device *spi = NULL; - char txbuf[256],rxbuf[256]; - ktime_t k1,k2; - - printk("%s:0:bus=0,cs=0; 1:bus=0,cs=1; 2:bus=1,cs=0; 3:bus=1,cs=1; 4:bus=2,cs=0; 5:bus=2,cs=1\n",__func__); - - if(count > 5) - return -EFAULT; - - ret = copy_from_user(nr_buf, buf, count); - if(ret < 0) - return -EFAULT; - - sscanf(nr_buf, "%d", &nr); - if(nr >= 6 || nr < 0) - { - printk("%s:cmd is error\n",__func__); - return -EFAULT; - } - - for(i=0; i<256; i++) - txbuf[i] = i; - - if(!g_spi_test_data[nr] || !g_spi_test_data[nr]->spi) - { - printk("%s:error g_spi_test_data is null\n",__func__); - return -EFAULT; - } - - spi = g_spi_test_data[nr]->spi; - k1 = ktime_get(); - for(i=0; i<5000; i++) - { - ret = spi_write(spi, txbuf, 256); - ret = spi_read(spi, rxbuf, 255); - ret = spi_write_then_read(spi,txbuf,254,rxbuf,253); - ret = spi_write_and_read(spi,txbuf,rxbuf,252); - ret = spi_write_and_read(spi,txbuf,rxbuf,251); - if(i%500==0) - printk("%s:test %d times\n\n",__func__,i+1); - } - k2 = ktime_get(); - k2 = ktime_sub(k2, k1); - if(!ret) - printk("%s:bus_num=%d,chip_select=%d,ok cost:%lldus data rate:%d Kbits/s\n",__func__,spi->master->bus_num, spi->chip_select, ktime_to_us(k2), 1536*5000*8/(s32)ktime_to_ms(k2)); - else - printk("%s:bus_num=%d,chip_select=%d,error\n",__func__,spi->master->bus_num, spi->chip_select); - - return count; -} - - -static const struct file_operations spi_test_fops = { - .write = spi_test_write, -}; - -static struct miscdevice spi_test_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "spi_misc_test", - .fops = &spi_test_fops, -}; - -#ifdef CONFIG_OF -static struct dw_spi_chip *rockchip_spi_parse_dt(struct device *dev) -{ - u32 temp; - struct dw_spi_chip *spi_chip_data; - - spi_chip_data = devm_kzalloc(dev, sizeof(*spi_chip_data), GFP_KERNEL); - if (!spi_chip_data) { - dev_err(dev, "memory allocation for spi_chip_data failed\n"); - return ERR_PTR(-ENOMEM); - } - - if (of_property_read_u32(dev->of_node, "poll_mode", &temp)) { - dev_warn(dev, "fail to get poll_mode, default set 0\n"); - spi_chip_data->poll_mode = 0; - } else { - spi_chip_data->poll_mode = temp; - } - - if (of_property_read_u32(dev->of_node, "type", &temp)) { - dev_warn(dev, "fail to get type, default set 0\n"); - spi_chip_data->type = 0; - } else { - spi_chip_data->type = temp; - } - - if (of_property_read_u32(dev->of_node, "enable_dma", &temp)) { - dev_warn(dev, "fail to get enable_dma, default set 0\n"); - spi_chip_data->enable_dma = 0; - } else { - spi_chip_data->enable_dma = temp; - } - - - return spi_chip_data; -} -#else -static struct spi_board_info *rockchip_spi_parse_dt(struct device *dev) -{ - return dev->platform_data; -} -#endif - - -static int rockchip_spi_test_probe(struct spi_device *spi) -{ - int ret; - int id = 0; - struct dw_spi_chip *spi_chip_data = NULL; - struct spi_test_data *spi_test_data = NULL; - - if(!spi) - return -ENOMEM; - - if (!spi_chip_data && spi->dev.of_node) { - spi_chip_data = rockchip_spi_parse_dt(&spi->dev); - if (IS_ERR(spi_chip_data)) - return -ENOMEM; - } - - spi_test_data = (struct spi_test_data *)kzalloc(sizeof(struct spi_test_data), GFP_KERNEL); - if(!spi_test_data){ - dev_err(&spi->dev, "ERR: no memory for spi_test_data\n"); - return -ENOMEM; - } - - spi->bits_per_word = 8; - spi->controller_data = spi_chip_data; - - spi_test_data->spi = spi; - spi_test_data->dev = &spi->dev; - - ret = spi_setup(spi); - if (ret < 0){ - dev_err(spi_test_data->dev, "ERR: fail to setup spi\n"); - return -1; - } - - if((spi->master->bus_num == 0) && (spi->chip_select == 0)) - id = 0; - else if((spi->master->bus_num == 0) && (spi->chip_select == 1)) - id = 1; - else if ((spi->master->bus_num == 1) && (spi->chip_select == 0)) - id = 2; - else if ((spi->master->bus_num == 1) && (spi->chip_select == 1)) - id = 3; - else if ((spi->master->bus_num == 2) && (spi->chip_select == 0)) - id = 4; - else if ((spi->master->bus_num == 2) && (spi->chip_select == 1)) - id = 5; - - g_spi_test_data[id] = spi_test_data; - - printk("%s:name=%s,bus_num=%d,cs=%d,mode=%d,speed=%d\n",__func__,spi->modalias, spi->master->bus_num, spi->chip_select, spi->mode, spi->max_speed_hz); - - printk("%s:poll_mode=%d, type=%d, enable_dma=%d\n",__func__, spi_chip_data->poll_mode, spi_chip_data->type, spi_chip_data->enable_dma); - return ret; - -} - -static int rockchip_spi_test_remove(struct spi_device *spi) -{ - printk("%s\n",__func__); - return 0; -} - -#ifdef CONFIG_OF -static const struct of_device_id rockchip_spi_test_dt_match[] = { - { .compatible = "rockchip,spi_test_bus0_cs0", }, - { .compatible = "rockchip,spi_test_bus0_cs1", }, - { .compatible = "rockchip,spi_test_bus1_cs0", }, - { .compatible = "rockchip,spi_test_bus1_cs1", }, - { .compatible = "rockchip,spi_test_bus2_cs0", }, - { .compatible = "rockchip,spi_test_bus2_cs1", }, - {}, -}; -MODULE_DEVICE_TABLE(of, rockchip_spi_test_dt_match); - -#endif /* CONFIG_OF */ - -static struct spi_driver spi_rockchip_test_driver = { - .driver = { - .name = "spi_test", - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(rockchip_spi_test_dt_match), - }, - .probe = rockchip_spi_test_probe, - .remove = rockchip_spi_test_remove, -}; - -static int __init spi_rockchip_test_init(void) -{ - int ret= 0; - misc_register(&spi_test_misc); - ret = spi_register_driver(&spi_rockchip_test_driver); - - return ret; -} -module_init(spi_rockchip_test_init); - -static void __exit spi_rockchip_test_exit(void) -{ - misc_deregister(&spi_test_misc); - return spi_unregister_driver(&spi_rockchip_test_driver); -} -module_exit(spi_rockchip_test_exit); - -MODULE_AUTHOR("Luo Wei "); -MODULE_DESCRIPTION("ROCKCHIP SPI TEST Driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("spi:spi_test"); - +/*drivers/spi/spi-rockchip-test.c -spi test driver + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* dts config +&spi0 { + status = "okay"; + max-freq = <48000000>; //spi internal clk, don't modify + //dma-names = "tx", "rx"; //enable dma + pinctrl-names = "default"; //pinctrl according to you board + pinctrl-0 = <&spi0_clk &spi0_tx &spi0_rx &spi0_cs0 &spi0_cs1>; + spi_test@00 { + compatible = "rockchip,spi_test_bus0_cs0"; + reg = <0>; //chip select 0:cs0 1:cs1 + spi-max-frequency = <24000000>; //spi output clock + //spi-cpha; not support + //spi-cpol; //if the property is here it is 1:clk is high, else 0:clk is low when idle + }; + + spi_test@01 { + compatible = "rockchip,spi_test_bus0_cs1"; + reg = <1>; + spi-max-frequency = <24000000>; + spi-cpha; + spi-cpol; + }; +}; +*/ + +/* how to test spi +* echo write 0 10 255 > /dev/spi_misc_test +* echo write 0 10 255 init.rc > /dev/spi_misc_test +* echo read 0 10 255 > /dev/spi_misc_test +* echo setspeed 0 1000000 > /dev/spi_misc_test +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "spi-rockchip-core.h" + +#define MAX_SPI_DEV_NUM 6 +#define SPI_MAX_SPEED_HZ 12000000 + +struct spi_test_data { + struct device *dev; + struct spi_device *spi; + char *rx_buf; + int rx_len; + char *tx_buf; + int tx_len; +}; + +static struct spi_test_data *g_spi_test_data[MAX_SPI_DEV_NUM]; + +int spi_write_slt(int id, const void *txbuf, size_t n) +{ + int ret = -1; + struct spi_device *spi = NULL; + + if (id >= MAX_SPI_DEV_NUM) + return -1; + if (!g_spi_test_data[id]) { + pr_err("g_spi.%d is NULL\n", id); + return -1; + } else { + spi = g_spi_test_data[id]->spi; + } + + ret = spi_write(spi, txbuf, n); + return ret; +} + +int spi_read_slt(int id, void *rxbuf, size_t n) +{ + int ret = -1; + struct spi_device *spi = NULL; + + if (id >= MAX_SPI_DEV_NUM) + return ret; + if (!g_spi_test_data[id]) { + pr_err("g_spi.%d is NULL\n", id); + return ret; + } else { + spi = g_spi_test_data[id]->spi; + } + + ret = spi_read(spi, rxbuf, n); + return ret; +} + +int spi_write_then_read_slt(int id, const void *txbuf, unsigned n_tx, + void *rxbuf, unsigned n_rx) +{ + int ret = -1; + struct spi_device *spi = NULL; + + if (id >= MAX_SPI_DEV_NUM) + return ret; + if (!g_spi_test_data[id]) { + pr_err("g_spi.%d is NULL\n", id); + return ret; + } else { + spi = g_spi_test_data[id]->spi; + } + + ret = spi_write_then_read(spi, txbuf, n_tx, rxbuf, n_rx); + return ret; +} + +int spi_write_and_read_slt(int id, const void *tx_buf, + void *rx_buf, size_t len) +{ + int ret = -1; + struct spi_device *spi = NULL; + struct spi_transfer t = { + .tx_buf = tx_buf, + .rx_buf = rx_buf, + .len = len, + }; + struct spi_message m; + + if (id >= MAX_SPI_DEV_NUM) + return ret; + if (!g_spi_test_data[id]) { + pr_err("g_spi.%d is NULL\n", id); + return ret; + } else { + spi = g_spi_test_data[id]->spi; + } + + spi_message_init(&m); + spi_message_add_tail(&t, &m); + return spi_sync(spi, &m); +} + +static ssize_t spi_test_write(struct file *file, + const char __user *buf, size_t n, loff_t *offset) +{ + int argc = 0, i; + char tmp[64]; + char *argv[16]; + char *cmd, *data; + unsigned int id = 0, times = 0, size = 0; + unsigned long us = 0, bytes = 0; + char *txbuf = NULL, *rxbuf = NULL; + ktime_t start_time; + ktime_t end_time; + ktime_t cost_time; + + memset(tmp, 0, sizeof(tmp)); + if (copy_from_user(tmp, buf, n)) + return -EFAULT; + cmd = tmp; + data = tmp; + + while (data < (tmp + n)) { + data = strstr(data, " "); + if (!data) + break; + *data = 0; + argv[argc] = ++data; + argc++; + if (argc >= 16) + break; + } + + tmp[n - 1] = 0; + + if (!strcmp(cmd, "setspeed")) { + int id = 0, val; + struct spi_device *spi = NULL; + + sscanf(argv[0], "%d", &id); + sscanf(argv[1], "%d", &val); + + if (id >= MAX_SPI_DEV_NUM) + return n; + if (!g_spi_test_data[id]) { + pr_err("g_spi.%d is NULL\n", id); + return n; + } else { + spi = g_spi_test_data[id]->spi; + } + spi->max_speed_hz = val; + } else if (!strcmp(cmd, "write")) { + char name[64]; + int fd; + mm_segment_t old_fs = get_fs(); + + sscanf(argv[0], "%d", &id); + sscanf(argv[1], "%d", ×); + sscanf(argv[2], "%d", &size); + if (argc > 3) { + sscanf(argv[3], "%s", name); + set_fs(KERNEL_DS); + } + + txbuf = kzalloc(size, GFP_KERNEL); + if (!txbuf) { + printk("spi write alloc buf size %d fail\n", size); + return n; + } + + if (argc > 3) { + fd = sys_open(name, O_RDONLY, 0); + if (fd < 0) { + printk("open %s fail\n", name); + } else { + sys_read(fd, (char __user *)txbuf, size); + sys_close(fd); + } + set_fs(old_fs); + } else { + for (i = 0; i < size; i++) + txbuf[i] = i % 256; + } + + start_time = ktime_get(); + for (i = 0; i < times; i++) + spi_write_slt(id, txbuf, size); + end_time = ktime_get(); + cost_time = ktime_sub(end_time, start_time); + us = ktime_to_us(cost_time); + + bytes = size * times * 1; + bytes = bytes * 1000 / us; + printk("spi write %d*%d cost %ldus speed:%ldKB/S\n", size, times, us, bytes); + + kfree(txbuf); + } else if (!strcmp(cmd, "read")) { + sscanf(argv[0], "%d", &id); + sscanf(argv[1], "%d", ×); + sscanf(argv[2], "%d", &size); + + rxbuf = kzalloc(size, GFP_KERNEL); + if (!rxbuf) { + printk("spi read alloc buf size %d fail\n", size); + return n; + } + + start_time = ktime_get(); + for (i = 0; i < times; i++) + spi_read_slt(id, rxbuf, size); + end_time = ktime_get(); + cost_time = ktime_sub(end_time, start_time); + us = ktime_to_us(cost_time); + + bytes = size * times * 1; + bytes = bytes * 1000 / us; + printk("spi read %d*%d cost %ldus speed:%ldKB/S\n", size, times, us, bytes); + + kfree(rxbuf); + } else if (!strcmp(cmd, "loop")) { + sscanf(argv[0], "%d", &id); + sscanf(argv[1], "%d", ×); + sscanf(argv[2], "%d", &size); + + txbuf = kzalloc(size, GFP_KERNEL); + if (!txbuf) { + printk("spi tx alloc buf size %d fail\n", size); + return n; + } + + rxbuf = kzalloc(size, GFP_KERNEL); + if (!rxbuf) { + kfree(txbuf); + printk("spi rx alloc buf size %d fail\n", size); + return n; + } + + for (i = 0; i < size; i++) + txbuf[i] = i % 256; + + start_time = ktime_get(); + for (i = 0; i < times; i++) + spi_write_and_read_slt(id, txbuf, rxbuf, size); + + end_time = ktime_get(); + cost_time = ktime_sub(end_time, start_time); + us = ktime_to_us(cost_time); + + if (memcmp(txbuf, rxbuf, size)) + printk("spi loop test fail\n"); + + bytes = size * times; + bytes = bytes * 1000 / us; + printk("spi loop %d*%d cost %ldus speed:%ldKB/S\n", size, times, us, bytes); + + kfree(txbuf); + kfree(rxbuf); + } else { + printk("echo write 0 10 255 > /dev/spi_misc_test\n"); + printk("echo write 0 10 255 init.rc > /dev/spi_misc_test\n"); + printk("echo read 0 10 255 > /dev/spi_misc_test\n"); + printk("echo setspeed 0 1000000 > /dev/spi_misc_test\n"); + } + + return n; +} + +static const struct file_operations spi_test_fops = { + .write = spi_test_write, +}; + +static struct miscdevice spi_test_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "spi_misc_test", + .fops = &spi_test_fops, +}; + +#ifdef CONFIG_OF +static struct dw_spi_chip *rockchip_spi_parse_dt(struct device *dev) +{ + u32 temp; + struct dw_spi_chip *spi_chip_data; + + spi_chip_data = devm_kzalloc(dev, sizeof(*spi_chip_data), GFP_KERNEL); + if (!spi_chip_data) { + dev_err(dev, "memory allocation for spi_chip_data failed\n"); + return ERR_PTR(-ENOMEM); + } + + if (of_property_read_u32(dev->of_node, "poll_mode", &temp)) { + dev_warn(dev, "fail to get poll_mode, default set 0\n"); + spi_chip_data->poll_mode = 0; + } else { + spi_chip_data->poll_mode = temp; + } + + if (of_property_read_u32(dev->of_node, "type", &temp)) { + dev_warn(dev, "fail to get type, default set 0\n"); + spi_chip_data->type = 0; + } else { + spi_chip_data->type = temp; + } + + if (of_property_read_u32(dev->of_node, "enable_dma", &temp)) { + dev_warn(dev, "fail to get enable_dma, default set 0\n"); + spi_chip_data->enable_dma = 0; + } else { + spi_chip_data->enable_dma = temp; + } +#if 0 + if (of_property_read_u32(dev->of_node, "slave-enable", &temp)) { + dev_warn(dev, "fail to get slave-enable, default set 0\n"); + spi_chip_data->slave_enable = 0; + } else { + spi_chip_data->slave_enable = temp; + } +#endif + return spi_chip_data; +} +#else +static struct spi_board_info *rockchip_spi_parse_dt(struct device *dev) +{ + return dev->platform_data; +} +#endif + +static int rockchip_spi_test_probe(struct spi_device *spi) +{ + int ret; + int id = 0; + struct dw_spi_chip *spi_chip_data = NULL; + struct spi_test_data *spi_test_data = NULL; + + if (!spi) + return -ENOMEM; + + if (!spi->dev.of_node) + return -ENOMEM; + + spi_chip_data = rockchip_spi_parse_dt(&spi->dev); + if (IS_ERR(spi_chip_data)) + return -ENOMEM; + + spi_test_data = (struct spi_test_data *)kzalloc(sizeof(struct spi_test_data), GFP_KERNEL); + if (!spi_test_data) { + dev_err(&spi->dev, "ERR: no memory for spi_test_data\n"); + return -ENOMEM; + } + spi->bits_per_word = 8; + spi->controller_data = spi_chip_data; + + spi_test_data->spi = spi; + spi_test_data->dev = &spi->dev; + + ret = spi_setup(spi); + if (ret < 0) { + dev_err(spi_test_data->dev, "ERR: fail to setup spi\n"); + return -1; + } + + if (of_property_read_u32(spi->dev.of_node, "id", &id)) { + dev_warn(&spi->dev, "fail to get id, default set 0\n"); + id = 0; + } + + g_spi_test_data[id] = spi_test_data; + + printk("%s:name=%s,bus_num=%d,cs=%d,mode=%d,speed=%d\n", __func__, spi->modalias, spi->master->bus_num, spi->chip_select, spi->mode, spi->max_speed_hz); + + printk("%s:poll_mode=%d, type=%d, enable_dma=%d\n", __func__, spi_chip_data->poll_mode, spi_chip_data->type, spi_chip_data->enable_dma); + return ret; +} + +static int rockchip_spi_test_remove(struct spi_device *spi) +{ + printk("%s\n", __func__); + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id rockchip_spi_test_dt_match[] = { + { .compatible = "rockchip,spi_test_bus0_cs0", }, + { .compatible = "rockchip,spi_test_bus0_cs1", }, + { .compatible = "rockchip,spi_test_bus1_cs0", }, + { .compatible = "rockchip,spi_test_bus1_cs1", }, + { .compatible = "rockchip,spi_test_bus2_cs0", }, + { .compatible = "rockchip,spi_test_bus2_cs1", }, + { .compatible = "rockchip,spi_test_bus3_cs0", }, + { .compatible = "rockchip,spi_test_bus3_cs1", }, + { .compatible = "rockchip,spi_test_bus4_cs0", }, + { .compatible = "rockchip,spi_test_bus4_cs1", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rockchip_spi_test_dt_match); + +#endif /* CONFIG_OF */ + +static struct spi_driver spi_rockchip_test_driver = { + .driver = { + .name = "spi_test", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rockchip_spi_test_dt_match), + }, + .probe = rockchip_spi_test_probe, + .remove = rockchip_spi_test_remove, +}; + +static int __init spi_rockchip_test_init(void) +{ + int ret = 0; + + misc_register(&spi_test_misc); + ret = spi_register_driver(&spi_rockchip_test_driver); + return ret; +} +module_init(spi_rockchip_test_init); + +static void __exit spi_rockchip_test_exit(void) +{ + misc_deregister(&spi_test_misc); + return spi_unregister_driver(&spi_rockchip_test_driver); +} +module_exit(spi_rockchip_test_exit); + +MODULE_AUTHOR("Luo Wei "); +MODULE_AUTHOR("Huibin Hong "); +MODULE_DESCRIPTION("ROCKCHIP SPI TEST Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:spi_test"); -- 2.34.1