Loading src/drivers/elphel/Makefile +3 −2 Original line number Original line Diff line number Diff line Loading @@ -8,5 +8,6 @@ obj-$(CONFIG_ELPHELDRVONMICROZED) += elphel393-mem.o obj-$(CONFIG_ELPHEL393_INIT) += elphel393-init.o obj-$(CONFIG_ELPHEL393_INIT) += elphel393-init.o obj-$(CONFIG_ELPHEL393) += x393.o obj-$(CONFIG_ELPHEL393) += x393.o obj-$(CONFIG_ELPHEL393) += sensor_i2c.o obj-$(CONFIG_ELPHEL393) += sensor_i2c.o fpgajtag-y := fpgajtag353.o x393.o obj-$(CONFIG_ELPHEL393) += fpgajtag353.o obj-$(CONFIG_ELPHEL393_EXTERNAL) += fpgajtag.o #fpgajtag-y := fpgajtag353.o x393.o No newline at end of file #obj-$(CONFIG_ELPHEL393_EXTERNAL) += fpgajtag.o No newline at end of file src/drivers/elphel/elphel393-mem.c +28 −25 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,10 @@ *! You should have received a copy of the GNU General Public License *! You should have received a copy of the GNU General Public License *! along with this program. If not, see <http://www.gnu.org/licenses/>. *! along with this program. If not, see <http://www.gnu.org/licenses/>. *!****************************************************************************/ *!****************************************************************************/ #define DRV_NAME "elphel393-mem" #define pr_fmt(fmt) DRV_NAME": " fmt #include <linux/module.h> #include <linux/module.h> #include <linux/init.h> #include <linux/init.h> #include <linux/of.h> #include <linux/of.h> Loading Loading @@ -74,7 +78,7 @@ static int __init elphelmem_init(void) node = of_find_node_by_name(NULL, "elphel393-mem"); node = of_find_node_by_name(NULL, "elphel393-mem"); if (!node) if (!node) { { printk("DMA buffer allocation ERROR: No device tree node found\n"); pr_err("DMA buffer allocation ERROR: No device tree node found\n"); return -ENODEV; return -ENODEV; } } Loading Loading @@ -116,34 +120,33 @@ static int __init elphelmem_init(void) // allocate continuous virtual memory range // allocate continuous virtual memory range // _elphel_buf.vaddr = kmalloc((_elphel_buf.size*PAGE_SIZE) ,GFP_KERNEL); // _elphel_buf.vaddr = kmalloc((_elphel_buf.size*PAGE_SIZE) ,GFP_KERNEL); _elphel_buf.vaddr = dma_alloc_coherent(NULL,(_elphel_buf.size*PAGE_SIZE),&(_elphel_buf.paddr),GFP_KERNEL); _elphel_buf.vaddr = dma_alloc_coherent(NULL,(_elphel_buf.size*PAGE_SIZE),&(_elphel_buf.paddr),GFP_KERNEL); if(_elphel_buf.paddr) { if(_elphel_buf.vaddr) { printk("Allocated %u pages for DMA at address 0x%x\n", (u32)_elphel_buf.size, (u32)_elphel_buf.paddr); pr_info("Allocated %u pages for DMA at address 0x%x\n", (u32)_elphel_buf.size, (u32)_elphel_buf.paddr); } else { } else { printk("ERROR allocating coherent DMA memory buffer"); pr_err("ERROR allocating coherent DMA memory buffer\n"); } } _elphel_buf.h2d_vaddr = kzalloc((_elphel_buf.h2d_size*PAGE_SIZE) ,GFP_KERNEL); _elphel_buf.h2d_vaddr = kzalloc((_elphel_buf.h2d_size*PAGE_SIZE) ,GFP_KERNEL); if (!_elphel_buf.h2d_vaddr){ if (!_elphel_buf.h2d_vaddr){ _elphel_buf.h2d_size = 0; _elphel_buf.h2d_size = 0; printk("ERROR allocating H2D DMA memory buffer"); pr_err("ERROR allocating H2D DMA memory buffer\n"); } } _elphel_buf.d2h_vaddr = kzalloc((_elphel_buf.d2h_size*PAGE_SIZE) ,GFP_KERNEL); _elphel_buf.d2h_vaddr = kzalloc((_elphel_buf.d2h_size*PAGE_SIZE) ,GFP_KERNEL); if (!_elphel_buf.d2h_vaddr){ if (!_elphel_buf.d2h_vaddr){ _elphel_buf.d2h_size = 0; _elphel_buf.d2h_size = 0; printk("ERROR allocating D2H DMA memory buffer"); pr_err("ERROR allocating D2H DMA memory buffer\n"); } } _elphel_buf.bidir_vaddr = kzalloc((_elphel_buf.bidir_size*PAGE_SIZE) ,GFP_KERNEL); _elphel_buf.bidir_vaddr = kzalloc((_elphel_buf.bidir_size*PAGE_SIZE) ,GFP_KERNEL); if (!_elphel_buf.bidir_vaddr){ if (!_elphel_buf.bidir_vaddr){ _elphel_buf.bidir_size = 0; _elphel_buf.bidir_size = 0; printk("ERROR allocating Bidirectional DMA memory buffer"); pr_err("ERROR allocating Bidirectional DMA memory buffer\n"); } } pr_info("Coherent buffer vaddr: 0x%08X\n",(u32) pElphel_buf -> vaddr); printk("Coherent buffer vaddr: 0x%08X\n",(u32) pElphel_buf -> vaddr); pr_info("Coherent buffer paddr: 0x%08X\n",(u32) pElphel_buf -> paddr); printk("Coherent buffer paddr: 0x%08X\n",(u32) pElphel_buf -> paddr); pr_info("Coherent buffer length: 0x%08X\n",(u32) pElphel_buf -> size * PAGE_SIZE); printk("Coherent buffer length: 0x%08X\n",(u32) pElphel_buf -> size * PAGE_SIZE); return 0; return 0; } } Loading @@ -155,7 +158,7 @@ dma_map_single(struct device *dev, void *cpu_addr, size_t size, */ */ static void __exit elphelmem_exit(void) static void __exit elphelmem_exit(void) { { printk("DMA buffer disabled\n"); pr_info("DMA buffer disabled\n"); } } Loading Loading @@ -240,7 +243,7 @@ static ssize_t sync_for_device_h2d(struct device *dev, struct device_attribute * paddr = _elphel_buf.h2d_paddr; paddr = _elphel_buf.h2d_paddr; len = _elphel_buf.h2d_size * PAGE_SIZE; len = _elphel_buf.h2d_size * PAGE_SIZE; } } printk("\naddr=0x%08x, size = 0x%08x\n", paddr, len); pr_info("\naddr=0x%08x, size = 0x%08x\n", paddr, len); dma_sync_single_for_device(dev, paddr, len, DMA_TO_DEVICE); dma_sync_single_for_device(dev, paddr, len, DMA_TO_DEVICE); return count; return count; Loading @@ -255,7 +258,7 @@ static ssize_t sync_for_cpu_d2h(struct device *dev, struct device_attribute *att paddr = _elphel_buf.d2h_paddr; paddr = _elphel_buf.d2h_paddr; len = _elphel_buf.d2h_size * PAGE_SIZE; len = _elphel_buf.d2h_size * PAGE_SIZE; } } printk("\naddr=0x%08x, size = 0x%08x\n", paddr, len); pr_info("\naddr=0x%08x, size = 0x%08x\n", paddr, len); dma_sync_single_for_cpu(dev, paddr, len, DMA_FROM_DEVICE); dma_sync_single_for_cpu(dev, paddr, len, DMA_FROM_DEVICE); return count; return count; Loading @@ -271,7 +274,7 @@ static ssize_t sync_for_device_d2h(struct device *dev, struct device_attribute * paddr = _elphel_buf.d2h_paddr; paddr = _elphel_buf.d2h_paddr; len = _elphel_buf.d2h_size * PAGE_SIZE; len = _elphel_buf.d2h_size * PAGE_SIZE; } } printk("\naddr=0x%08x, size = 0x%08x\n", paddr, len); pr_info("\naddr=0x%08x, size = 0x%08x\n", paddr, len); dma_sync_single_for_device(dev, paddr, len, DMA_FROM_DEVICE); dma_sync_single_for_device(dev, paddr, len, DMA_FROM_DEVICE); return count; return count; Loading @@ -286,7 +289,7 @@ static ssize_t sync_for_cpu_bidir(struct device *dev, struct device_attribute *a paddr = _elphel_buf.bidir_paddr; paddr = _elphel_buf.bidir_paddr; len = _elphel_buf.bidir_size * PAGE_SIZE; len = _elphel_buf.bidir_size * PAGE_SIZE; } } printk("\naddr=0x%08x, size = 0x%08x\n", paddr, len); pr_info("\naddr=0x%08x, size = 0x%08x\n", paddr, len); dma_sync_single_for_cpu(dev, paddr, len, DMA_BIDIRECTIONAL); dma_sync_single_for_cpu(dev, paddr, len, DMA_BIDIRECTIONAL); return count; return count; Loading @@ -302,7 +305,7 @@ static ssize_t sync_for_device_bidir(struct device *dev, struct device_attribute paddr = _elphel_buf.bidir_paddr; paddr = _elphel_buf.bidir_paddr; len = _elphel_buf.bidir_size * PAGE_SIZE; len = _elphel_buf.bidir_size * PAGE_SIZE; } } printk("\naddr=0x%08x, size = 0x%08x\n", paddr, len); pr_info("\naddr=0x%08x, size = 0x%08x\n", paddr, len); dma_sync_single_for_device(dev, paddr, len, DMA_BIDIRECTIONAL); dma_sync_single_for_device(dev, paddr, len, DMA_BIDIRECTIONAL); return count; return count; Loading Loading @@ -386,13 +389,13 @@ static int elphel393_mem_sysfs_register(struct platform_device *pdev) static int elphel393_mem_probe(struct platform_device *pdev) static int elphel393_mem_probe(struct platform_device *pdev) { { elphel393_mem_sysfs_register(pdev); elphel393_mem_sysfs_register(pdev); dev_info(&pdev->dev,"Probing elphel393-mem\n"); pr_info("Probing elphel393-mem\n"); if (_elphel_buf.h2d_vaddr){ if (_elphel_buf.h2d_vaddr){ // mapped as DMA_BIDIRECTIONAL, each time will be synchronized when passing control from soft to hard and back // mapped as DMA_BIDIRECTIONAL, each time will be synchronized when passing control from soft to hard and back pElphel_buf->h2d_paddr = dma_map_single(&pdev->dev, _elphel_buf.h2d_vaddr, (_elphel_buf.h2d_size*PAGE_SIZE), DMA_TO_DEVICE); pElphel_buf->h2d_paddr = dma_map_single(&pdev->dev, _elphel_buf.h2d_vaddr, (_elphel_buf.h2d_size*PAGE_SIZE), DMA_TO_DEVICE); if (!pElphel_buf->h2d_paddr){ if (!pElphel_buf->h2d_paddr){ printk("ERROR in dma_map_single() for bidirectional buffer"); pr_err("ERROR in dma_map_single() for bidirectional buffer\n"); return 0; return 0; } } // printk("H2D DMA buffer location:\t\t0x%08X\n", pElphel_buf->h2d_paddr); // printk("H2D DMA buffer location:\t\t0x%08X\n", pElphel_buf->h2d_paddr); Loading @@ -402,7 +405,7 @@ static int elphel393_mem_probe(struct platform_device *pdev) // mapped as DMA_BIDIRECTIONAL, each time will be synchronized when passing control from soft to hard and back // mapped as DMA_BIDIRECTIONAL, each time will be synchronized when passing control from soft to hard and back pElphel_buf->d2h_paddr = dma_map_single(&pdev->dev, _elphel_buf.d2h_vaddr, (_elphel_buf.d2h_size*PAGE_SIZE), DMA_FROM_DEVICE); pElphel_buf->d2h_paddr = dma_map_single(&pdev->dev, _elphel_buf.d2h_vaddr, (_elphel_buf.d2h_size*PAGE_SIZE), DMA_FROM_DEVICE); if (!pElphel_buf->d2h_paddr){ if (!pElphel_buf->d2h_paddr){ printk("ERROR in dma_map_single() for bidirectional buffer"); pr_err("ERROR in dma_map_single() for bidirectional buffer\n"); return 0; return 0; } } // printk("D2H DMA buffer location:\t\t0x%08X\n", pElphel_buf->d2h_paddr); // printk("D2H DMA buffer location:\t\t0x%08X\n", pElphel_buf->d2h_paddr); Loading @@ -413,7 +416,7 @@ static int elphel393_mem_probe(struct platform_device *pdev) // mapped as DMA_BIDIRECTIONAL, each time will be synchronized when passing control from soft to hard and back // mapped as DMA_BIDIRECTIONAL, each time will be synchronized when passing control from soft to hard and back pElphel_buf->bidir_paddr = dma_map_single(&pdev->dev, _elphel_buf.bidir_vaddr, (_elphel_buf.bidir_size*PAGE_SIZE), DMA_BIDIRECTIONAL); pElphel_buf->bidir_paddr = dma_map_single(&pdev->dev, _elphel_buf.bidir_vaddr, (_elphel_buf.bidir_size*PAGE_SIZE), DMA_BIDIRECTIONAL); if (!pElphel_buf->bidir_paddr){ if (!pElphel_buf->bidir_paddr){ printk("ERROR in dma_map_single() for bidirectional buffer"); pr_err("ERROR in dma_map_single() for bidirectional buffer\n"); return 0; return 0; } } // printk("Bidirectional DMA buffer location:\t0x%08X\n", pElphel_buf->bidir_paddr); // printk("Bidirectional DMA buffer location:\t0x%08X\n", pElphel_buf->bidir_paddr); Loading @@ -438,7 +441,7 @@ static int elphel393_mem_probe(struct platform_device *pdev) static int elphel393_mem_remove(struct platform_device *pdev) static int elphel393_mem_remove(struct platform_device *pdev) { { dev_info(&pdev->dev,"Removing elphel393-mem"); pr_info("Removing elphel393-mem"); return 0; return 0; } } Loading @@ -452,7 +455,7 @@ static struct platform_driver elphel393_mem = { .probe = elphel393_mem_probe, .probe = elphel393_mem_probe, .remove = elphel393_mem_remove, .remove = elphel393_mem_remove, .driver = { .driver = { .name = "elphel393-mem", .name = DRV_NAME, .owner = THIS_MODULE, .owner = THIS_MODULE, .of_match_table = elphel393_mem_of_match, .of_match_table = elphel393_mem_of_match, .pm = NULL, /* power management */ .pm = NULL, /* power management */ Loading @@ -463,5 +466,5 @@ module_platform_driver(elphel393_mem); module_init(elphelmem_init); module_init(elphelmem_init); module_exit(elphelmem_exit); module_exit(elphelmem_exit); MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Elphel, Inc."); MODULE_DESCRIPTION("Reserve a large chunk of contiguous memory at boot"); src/drivers/elphel/sensor_i2c.c +166 −31 Original line number Original line Diff line number Diff line Loading @@ -289,8 +289,8 @@ static ssize_t get_i2c_page_alloc(struct device *dev, struct device_attribute *a { { int chn = get_channel_from_name(attr) ; int chn = get_channel_from_name(attr) ; int page; int page; if (sysfs_page[chn]>=0) // if (sysfs_page[chn]>=0) return -EBUSY; // return -EBUSY; page= i2c_page_alloc(chn); page= i2c_page_alloc(chn); if (page <0) if (page <0) return -ENOMEM; return -ENOMEM; Loading @@ -303,17 +303,30 @@ static ssize_t free_i2c_page(struct device *dev, struct device_attribute *attr, int page; int page; sscanf(buf, "%i", &page); sscanf(buf, "%i", &page); page &= 0xff; page &= 0xff; if (sysfs_page[chn] >= 0) // if (sysfs_page[chn] >= 0) // i2c_page_free(chn, page); // sysfs_page[chn] = -1; // free i2c_page_free(chn, page); i2c_page_free(chn, page); sysfs_page[chn] = -1; // free return count; return count; } } /* Set/get page number for reading */ static ssize_t set_i2c_page_inuse(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int chn = get_channel_from_name(attr) ; int page; sscanf(buf, "%i", &page); sysfs_page[chn] = page & 0xff; return count; } static ssize_t get_i2c_page_inuse(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t get_i2c_page_inuse(struct device *dev, struct device_attribute *attr, char *buf) { { int chn = get_channel_from_name(attr) ; int chn = get_channel_from_name(attr) ; return sprintf(buf,"%d\n",sysfs_page[chn]); return sprintf(buf,"%d\n",sysfs_page[chn]); } } // Get i2c table data as raw data (hex) // Get i2c table data as raw data (hex) static ssize_t get_i2c_tbl_raw(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t get_i2c_tbl_raw(struct device *dev, struct device_attribute *attr, char *buf) { { Loading @@ -322,49 +335,170 @@ static ssize_t get_i2c_tbl_raw(struct device *dev, struct device_attribute *attr if (page < 0) if (page < 0) return -ENXIO; /* No such device or address */ return -ENXIO; /* No such device or address */ return sprintf(buf,"%0x08x\n",i2c_pages_shadow[(chn << 8) + (page &0xff)]); return sprintf(buf,"0x%08x\n",i2c_pages_shadow[(chn << 8) + (page &0xff)]); } } static ssize_t set_i2c_tbl_raw(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) static ssize_t set_i2c_tbl_raw(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { { int chn = get_channel_from_name(attr) ; int chn = get_channel_from_name(attr) ; int page, data; int ni, page, data; sscanf(buf, "%i %i", &page, &data); ni = sscanf(buf, "%i %i", &page, &data); page &= 0xff; if (ni < 2) dev_err(dev, "Requires 2 parameters: page, data\n"); return -EINVAL; set_sensor_i2c_raw(chn, set_sensor_i2c_raw(chn, page, // index in lookup table page & 0xff, // index in lookup table (u32) data); // Bit delay - number of mclk periods in 1/4 of the SCL period (u32) data); // Bit delay - number of mclk periods in 1/4 of the SCL period return count; return count; } } // Sysfs top // Get/parse i2c table (hex) static ssize_t get_i2c_tbl_human(struct device *dev, struct device_attribute *attr, char *buf) { x393_i2c_ctltbl_t tb_data; int chn = get_channel_from_name(attr) ; int page = sysfs_page[chn]; // currently selected page for sysfs reads if (page < 0) return -ENXIO; /* No such device or address */ tb_data.d32 = i2c_pages_shadow[(chn << 8) + (page &0xff)]; if (tb_data.rnw){ return sprintf(buf,"Read entry: chn=%d page=%d(0x%x) two_byte_addr=%d number bytes to read=%d bit_duration=%d\n", chn, page,page, tb_data.nabrd,tb_data.nabrd,tb_data.nbrd, tb_data.dly); } else { return sprintf(buf,"Write entry: chn=%d page=%d(0x%x) sa=0x%02x rah=0x%02x nbw=%d bit_duration=%d\n", chn, page,page,tb_data.sa,tb_data.rah,tb_data.nbwr, tb_data.dly); } } static ssize_t set_i2c_tbl_wr_human(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int chn = get_channel_from_name(attr) ; int ni, page, rah,sa7,nbwr,dly; ni = sscanf(buf, "%i %i %i %i %i", &page, &sa7, &rah, &nbwr, &dly); if (ni < 2) dev_err(dev, "Requires 5 parameters: page, slave address (7 bit), high reg address byte, bytes to write (1..10), 1/4 scl period in mclk\n"); return -EINVAL; set_sensor_i2c_wr(chn, page & 0xff, // index in lookup table sa7 & 0x7f, // slave address (7 bit) rah & 0xff, // High byte of the i2c register address nbwr & 0xf, // Number of bytes to write (1..10) dly & 0xff); // Bit delay - number of mclk periods in 1/4 of the SCL period return count; } static DEVICE_ATTR(alloc0 , SYSFS_PERMISSIONS & SYSFS_READONLY, get_i2c_page_alloc , NULL); static ssize_t set_i2c_tbl_rd_human(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) static DEVICE_ATTR(alloc1 , SYSFS_PERMISSIONS & SYSFS_READONLY, get_i2c_page_alloc , NULL); { static DEVICE_ATTR(alloc2 , SYSFS_PERMISSIONS & SYSFS_READONLY, get_i2c_page_alloc , NULL); int chn = get_channel_from_name(attr) ; static DEVICE_ATTR(alloc3 , SYSFS_PERMISSIONS & SYSFS_READONLY, get_i2c_page_alloc , NULL); int ni, page, two_byte_addr, num_bytes,bit_delay; static DEVICE_ATTR(page_in_use0 , SYSFS_PERMISSIONS , get_i2c_page_inuse, free_i2c_page); ni = sscanf(buf, "%i %i %i %i %i", &page, &two_byte_addr, &num_bytes, &bit_delay); static DEVICE_ATTR(page_in_use1 , SYSFS_PERMISSIONS , get_i2c_page_inuse, free_i2c_page); if (ni < 2) static DEVICE_ATTR(page_in_use2 , SYSFS_PERMISSIONS , get_i2c_page_inuse, free_i2c_page); dev_err(dev, "Requires 4 parameters: page, two byte addr (0 - 8bit,1 - 16 bit reg. addr), number of bytes to read, bytes to write (1..10), 1/4 scl period in mclk\n"); static DEVICE_ATTR(page_in_use3 , SYSFS_PERMISSIONS , get_i2c_page_inuse, free_i2c_page); return -EINVAL; set_sensor_i2c_rd( chn, page & 0xff, // index in lookup table two_byte_addr & 1, // Number of address bytes (0 - one byte, 1 - two bytes) num_bytes & 7, // Number of bytes to read (1..8, 0 means 8) bit_delay & 0xff); // Bit delay - number of mclk periods in 1/4 of the SCL period return count; } static ssize_t set_i2c_read(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int chn = get_channel_from_name(attr) ; int ni, page, sa7, addr; ni = sscanf(buf, "%i %i %i", &page, &sa7, addr); if (ni <3) dev_err(dev, "Requires 3 parameters: page, sa7, reg_addr\n"); return -EINVAL; page &= 0xff; read_sensor_i2c (chn, page & 0xff, // page (8 bits) sa7 & 0x7f, // 7-bit i2c slave address addr & 0xffff); // 8/16 bit address return count; } // Get i2c read data from fifo static ssize_t get_i2c_read(struct device *dev, struct device_attribute *attr, char *buf) { int chn = get_channel_from_name(attr) ; int page = sysfs_page[chn]; // currently selected page for sysfs reads if (page < 0) return -ENXIO; /* No such device or address */ return sprintf(buf,"%d\n",read_sensor_i2c_fifo(chn)); // <0 - not ready, 0..255 - data } // Get i2c read data from fifo static ssize_t get_i2c_help(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf,"Numeric suffix in file names selects sensor port\n" "alloc*: read - allocate and return page, write <page> (any data) - free page\n" "rd_page*: read/write page number used in read operations (-1 if none)\n" "tbl_raw*: read - raw hex table value (for current rd_page), write <page> <data32> set page\n" "tbl_wr*: read - decoded table entry for current rd_page, write <page> <sa7> <high_addr_byte> <bytes_to_write> <dly>\n" "tbl_rd*: read - decoded table entry for current rd_page, write <page> <2-byte addr> <bytes_to_read> <dly>\n" "tbl_rd* and tbl_wr* return same result when read. Delay is 8 bit, 250 - 200KHz SCL\n"); } // Sysfs top /* alloc*: read - allocate and return page, write (any data) - free page */ static DEVICE_ATTR(alloc0 , SYSFS_PERMISSIONS , get_i2c_page_alloc , free_i2c_page); static DEVICE_ATTR(alloc1 , SYSFS_PERMISSIONS , get_i2c_page_alloc , free_i2c_page); static DEVICE_ATTR(alloc2 , SYSFS_PERMISSIONS , get_i2c_page_alloc , free_i2c_page); static DEVICE_ATTR(alloc3 , SYSFS_PERMISSIONS , get_i2c_page_alloc , free_i2c_page); /* rd_page*: read/write page number used in read operations */ static DEVICE_ATTR(rd_page0 , SYSFS_PERMISSIONS , get_i2c_page_inuse, set_i2c_page_inuse); static DEVICE_ATTR(rd_page1 , SYSFS_PERMISSIONS , get_i2c_page_inuse, set_i2c_page_inuse); static DEVICE_ATTR(rd_page2 , SYSFS_PERMISSIONS , get_i2c_page_inuse, set_i2c_page_inuse); static DEVICE_ATTR(rd_page3 , SYSFS_PERMISSIONS , get_i2c_page_inuse, set_i2c_page_inuse); static DEVICE_ATTR(tbl_raw0 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw); static DEVICE_ATTR(tbl_raw0 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw); static DEVICE_ATTR(tbl_raw1 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw); static DEVICE_ATTR(tbl_raw1 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw); static DEVICE_ATTR(tbl_raw2 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw); static DEVICE_ATTR(tbl_raw2 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw); static DEVICE_ATTR(tbl_raw3 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw); static DEVICE_ATTR(tbl_raw3 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw); static DEVICE_ATTR(tbl_wr0 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_wr_human); static DEVICE_ATTR(tbl_wr1 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_wr_human); static DEVICE_ATTR(tbl_wr2 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_wr_human); static DEVICE_ATTR(tbl_wr3 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_wr_human); static DEVICE_ATTR(tbl_rd0 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_rd_human); static DEVICE_ATTR(tbl_rd1 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_rd_human); static DEVICE_ATTR(tbl_rd2 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_rd_human); static DEVICE_ATTR(tbl_rd3 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_rd_human); static DEVICE_ATTR(i2c_rd0 , SYSFS_PERMISSIONS , get_i2c_read, set_i2c_read); static DEVICE_ATTR(i2c_rd1 , SYSFS_PERMISSIONS , get_i2c_read, set_i2c_read); static DEVICE_ATTR(i2c_rd2 , SYSFS_PERMISSIONS , get_i2c_read, set_i2c_read); static DEVICE_ATTR(i2c_rd3 , SYSFS_PERMISSIONS , get_i2c_read, set_i2c_read); static DEVICE_ATTR(help, SYSFS_PERMISSIONS & SYSFS_READONLY, get_i2c_help, NULL); static struct attribute *root_dev_attrs[] = { static struct attribute *root_dev_attrs[] = { &dev_attr_alloc0.attr, &dev_attr_alloc0.attr, &dev_attr_alloc1.attr, &dev_attr_alloc1.attr, &dev_attr_alloc2.attr, &dev_attr_alloc2.attr, &dev_attr_alloc3.attr, &dev_attr_alloc3.attr, &dev_attr_page_in_use0.attr, &dev_attr_rd_page0.attr, &dev_attr_page_in_use1.attr, &dev_attr_rd_page1.attr, &dev_attr_page_in_use2.attr, &dev_attr_rd_page2.attr, &dev_attr_page_in_use3.attr, &dev_attr_rd_page3.attr, &dev_attr_tbl_raw0.attr, &dev_attr_tbl_raw0.attr, &dev_attr_tbl_raw1.attr, &dev_attr_tbl_raw1.attr, &dev_attr_tbl_raw2.attr, &dev_attr_tbl_raw2.attr, &dev_attr_tbl_raw3.attr, &dev_attr_tbl_raw3.attr, &dev_attr_tbl_wr0.attr, &dev_attr_tbl_wr1.attr, &dev_attr_tbl_wr2.attr, &dev_attr_tbl_wr3.attr, &dev_attr_tbl_rd0.attr, &dev_attr_tbl_rd1.attr, &dev_attr_tbl_rd2.attr, &dev_attr_tbl_rd3.attr, &dev_attr_i2c_rd0.attr, &dev_attr_i2c_rd1.attr, &dev_attr_i2c_rd2.attr, &dev_attr_i2c_rd3.attr, &dev_attr_help.attr, NULL NULL }; }; Loading Loading @@ -412,13 +546,14 @@ static int elphel393_sensor_i2c_probe(struct platform_device *pdev) struct i2c_client *ltc3589_client; struct i2c_client *ltc3589_client; struct elphel393_pwr_data_t *clientdata = NULL; struct elphel393_pwr_data_t *clientdata = NULL; */ */ dev_info(&pdev->dev,"Probing elphel393-sensor-i2c\n"); pr_info("Probing elphel393-sensor-i2c\n"); elphel393_sens_i2c_sysfs_register(pdev); i2c_page_alloc_init(); i2c_page_alloc_init(); #if 0 #if 0 clientdata = devm_kzalloc(&pdev->dev, sizeof(*clientdata), GFP_KERNEL); clientdata = devm_kzalloc(&pdev->dev, sizeof(*clientdata), GFP_KERNEL); #endif #endif elphel393_sensor_i2c_init_of(pdev); elphel393_sensor_i2c_init_of(pdev); elphel393_sens_i2c_sysfs_register(pdev); pr_info("done probing elphel393-sensor-i2c\n"); return 0; return 0; } } Loading @@ -435,7 +570,7 @@ static struct of_device_id elphel393_sensor_i2c_of_match[] = { MODULE_DEVICE_TABLE(of, elphel393_sensor_i2c_of_match); MODULE_DEVICE_TABLE(of, elphel393_sensor_i2c_of_match); static struct platform_driver elphel393_pwr = { static struct platform_driver elphel393_sensor_i2c = { .probe = elphel393_sensor_i2c_probe, .probe = elphel393_sensor_i2c_probe, .remove = elphel393_sensor_i2c_remove, .remove = elphel393_sensor_i2c_remove, .driver = { .driver = { Loading @@ -446,7 +581,7 @@ static struct platform_driver elphel393_pwr = { }, }, }; }; module_platform_driver(elphel393_pwr); module_platform_driver(elphel393_sensor_i2c); MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>"); MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>"); MODULE_DESCRIPTION("Elphel 10393 sensor ports i2c"); MODULE_DESCRIPTION("Elphel 10393 sensor ports i2c"); Loading Loading
src/drivers/elphel/Makefile +3 −2 Original line number Original line Diff line number Diff line Loading @@ -8,5 +8,6 @@ obj-$(CONFIG_ELPHELDRVONMICROZED) += elphel393-mem.o obj-$(CONFIG_ELPHEL393_INIT) += elphel393-init.o obj-$(CONFIG_ELPHEL393_INIT) += elphel393-init.o obj-$(CONFIG_ELPHEL393) += x393.o obj-$(CONFIG_ELPHEL393) += x393.o obj-$(CONFIG_ELPHEL393) += sensor_i2c.o obj-$(CONFIG_ELPHEL393) += sensor_i2c.o fpgajtag-y := fpgajtag353.o x393.o obj-$(CONFIG_ELPHEL393) += fpgajtag353.o obj-$(CONFIG_ELPHEL393_EXTERNAL) += fpgajtag.o #fpgajtag-y := fpgajtag353.o x393.o No newline at end of file #obj-$(CONFIG_ELPHEL393_EXTERNAL) += fpgajtag.o No newline at end of file
src/drivers/elphel/elphel393-mem.c +28 −25 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,10 @@ *! You should have received a copy of the GNU General Public License *! You should have received a copy of the GNU General Public License *! along with this program. If not, see <http://www.gnu.org/licenses/>. *! along with this program. If not, see <http://www.gnu.org/licenses/>. *!****************************************************************************/ *!****************************************************************************/ #define DRV_NAME "elphel393-mem" #define pr_fmt(fmt) DRV_NAME": " fmt #include <linux/module.h> #include <linux/module.h> #include <linux/init.h> #include <linux/init.h> #include <linux/of.h> #include <linux/of.h> Loading Loading @@ -74,7 +78,7 @@ static int __init elphelmem_init(void) node = of_find_node_by_name(NULL, "elphel393-mem"); node = of_find_node_by_name(NULL, "elphel393-mem"); if (!node) if (!node) { { printk("DMA buffer allocation ERROR: No device tree node found\n"); pr_err("DMA buffer allocation ERROR: No device tree node found\n"); return -ENODEV; return -ENODEV; } } Loading Loading @@ -116,34 +120,33 @@ static int __init elphelmem_init(void) // allocate continuous virtual memory range // allocate continuous virtual memory range // _elphel_buf.vaddr = kmalloc((_elphel_buf.size*PAGE_SIZE) ,GFP_KERNEL); // _elphel_buf.vaddr = kmalloc((_elphel_buf.size*PAGE_SIZE) ,GFP_KERNEL); _elphel_buf.vaddr = dma_alloc_coherent(NULL,(_elphel_buf.size*PAGE_SIZE),&(_elphel_buf.paddr),GFP_KERNEL); _elphel_buf.vaddr = dma_alloc_coherent(NULL,(_elphel_buf.size*PAGE_SIZE),&(_elphel_buf.paddr),GFP_KERNEL); if(_elphel_buf.paddr) { if(_elphel_buf.vaddr) { printk("Allocated %u pages for DMA at address 0x%x\n", (u32)_elphel_buf.size, (u32)_elphel_buf.paddr); pr_info("Allocated %u pages for DMA at address 0x%x\n", (u32)_elphel_buf.size, (u32)_elphel_buf.paddr); } else { } else { printk("ERROR allocating coherent DMA memory buffer"); pr_err("ERROR allocating coherent DMA memory buffer\n"); } } _elphel_buf.h2d_vaddr = kzalloc((_elphel_buf.h2d_size*PAGE_SIZE) ,GFP_KERNEL); _elphel_buf.h2d_vaddr = kzalloc((_elphel_buf.h2d_size*PAGE_SIZE) ,GFP_KERNEL); if (!_elphel_buf.h2d_vaddr){ if (!_elphel_buf.h2d_vaddr){ _elphel_buf.h2d_size = 0; _elphel_buf.h2d_size = 0; printk("ERROR allocating H2D DMA memory buffer"); pr_err("ERROR allocating H2D DMA memory buffer\n"); } } _elphel_buf.d2h_vaddr = kzalloc((_elphel_buf.d2h_size*PAGE_SIZE) ,GFP_KERNEL); _elphel_buf.d2h_vaddr = kzalloc((_elphel_buf.d2h_size*PAGE_SIZE) ,GFP_KERNEL); if (!_elphel_buf.d2h_vaddr){ if (!_elphel_buf.d2h_vaddr){ _elphel_buf.d2h_size = 0; _elphel_buf.d2h_size = 0; printk("ERROR allocating D2H DMA memory buffer"); pr_err("ERROR allocating D2H DMA memory buffer\n"); } } _elphel_buf.bidir_vaddr = kzalloc((_elphel_buf.bidir_size*PAGE_SIZE) ,GFP_KERNEL); _elphel_buf.bidir_vaddr = kzalloc((_elphel_buf.bidir_size*PAGE_SIZE) ,GFP_KERNEL); if (!_elphel_buf.bidir_vaddr){ if (!_elphel_buf.bidir_vaddr){ _elphel_buf.bidir_size = 0; _elphel_buf.bidir_size = 0; printk("ERROR allocating Bidirectional DMA memory buffer"); pr_err("ERROR allocating Bidirectional DMA memory buffer\n"); } } pr_info("Coherent buffer vaddr: 0x%08X\n",(u32) pElphel_buf -> vaddr); printk("Coherent buffer vaddr: 0x%08X\n",(u32) pElphel_buf -> vaddr); pr_info("Coherent buffer paddr: 0x%08X\n",(u32) pElphel_buf -> paddr); printk("Coherent buffer paddr: 0x%08X\n",(u32) pElphel_buf -> paddr); pr_info("Coherent buffer length: 0x%08X\n",(u32) pElphel_buf -> size * PAGE_SIZE); printk("Coherent buffer length: 0x%08X\n",(u32) pElphel_buf -> size * PAGE_SIZE); return 0; return 0; } } Loading @@ -155,7 +158,7 @@ dma_map_single(struct device *dev, void *cpu_addr, size_t size, */ */ static void __exit elphelmem_exit(void) static void __exit elphelmem_exit(void) { { printk("DMA buffer disabled\n"); pr_info("DMA buffer disabled\n"); } } Loading Loading @@ -240,7 +243,7 @@ static ssize_t sync_for_device_h2d(struct device *dev, struct device_attribute * paddr = _elphel_buf.h2d_paddr; paddr = _elphel_buf.h2d_paddr; len = _elphel_buf.h2d_size * PAGE_SIZE; len = _elphel_buf.h2d_size * PAGE_SIZE; } } printk("\naddr=0x%08x, size = 0x%08x\n", paddr, len); pr_info("\naddr=0x%08x, size = 0x%08x\n", paddr, len); dma_sync_single_for_device(dev, paddr, len, DMA_TO_DEVICE); dma_sync_single_for_device(dev, paddr, len, DMA_TO_DEVICE); return count; return count; Loading @@ -255,7 +258,7 @@ static ssize_t sync_for_cpu_d2h(struct device *dev, struct device_attribute *att paddr = _elphel_buf.d2h_paddr; paddr = _elphel_buf.d2h_paddr; len = _elphel_buf.d2h_size * PAGE_SIZE; len = _elphel_buf.d2h_size * PAGE_SIZE; } } printk("\naddr=0x%08x, size = 0x%08x\n", paddr, len); pr_info("\naddr=0x%08x, size = 0x%08x\n", paddr, len); dma_sync_single_for_cpu(dev, paddr, len, DMA_FROM_DEVICE); dma_sync_single_for_cpu(dev, paddr, len, DMA_FROM_DEVICE); return count; return count; Loading @@ -271,7 +274,7 @@ static ssize_t sync_for_device_d2h(struct device *dev, struct device_attribute * paddr = _elphel_buf.d2h_paddr; paddr = _elphel_buf.d2h_paddr; len = _elphel_buf.d2h_size * PAGE_SIZE; len = _elphel_buf.d2h_size * PAGE_SIZE; } } printk("\naddr=0x%08x, size = 0x%08x\n", paddr, len); pr_info("\naddr=0x%08x, size = 0x%08x\n", paddr, len); dma_sync_single_for_device(dev, paddr, len, DMA_FROM_DEVICE); dma_sync_single_for_device(dev, paddr, len, DMA_FROM_DEVICE); return count; return count; Loading @@ -286,7 +289,7 @@ static ssize_t sync_for_cpu_bidir(struct device *dev, struct device_attribute *a paddr = _elphel_buf.bidir_paddr; paddr = _elphel_buf.bidir_paddr; len = _elphel_buf.bidir_size * PAGE_SIZE; len = _elphel_buf.bidir_size * PAGE_SIZE; } } printk("\naddr=0x%08x, size = 0x%08x\n", paddr, len); pr_info("\naddr=0x%08x, size = 0x%08x\n", paddr, len); dma_sync_single_for_cpu(dev, paddr, len, DMA_BIDIRECTIONAL); dma_sync_single_for_cpu(dev, paddr, len, DMA_BIDIRECTIONAL); return count; return count; Loading @@ -302,7 +305,7 @@ static ssize_t sync_for_device_bidir(struct device *dev, struct device_attribute paddr = _elphel_buf.bidir_paddr; paddr = _elphel_buf.bidir_paddr; len = _elphel_buf.bidir_size * PAGE_SIZE; len = _elphel_buf.bidir_size * PAGE_SIZE; } } printk("\naddr=0x%08x, size = 0x%08x\n", paddr, len); pr_info("\naddr=0x%08x, size = 0x%08x\n", paddr, len); dma_sync_single_for_device(dev, paddr, len, DMA_BIDIRECTIONAL); dma_sync_single_for_device(dev, paddr, len, DMA_BIDIRECTIONAL); return count; return count; Loading Loading @@ -386,13 +389,13 @@ static int elphel393_mem_sysfs_register(struct platform_device *pdev) static int elphel393_mem_probe(struct platform_device *pdev) static int elphel393_mem_probe(struct platform_device *pdev) { { elphel393_mem_sysfs_register(pdev); elphel393_mem_sysfs_register(pdev); dev_info(&pdev->dev,"Probing elphel393-mem\n"); pr_info("Probing elphel393-mem\n"); if (_elphel_buf.h2d_vaddr){ if (_elphel_buf.h2d_vaddr){ // mapped as DMA_BIDIRECTIONAL, each time will be synchronized when passing control from soft to hard and back // mapped as DMA_BIDIRECTIONAL, each time will be synchronized when passing control from soft to hard and back pElphel_buf->h2d_paddr = dma_map_single(&pdev->dev, _elphel_buf.h2d_vaddr, (_elphel_buf.h2d_size*PAGE_SIZE), DMA_TO_DEVICE); pElphel_buf->h2d_paddr = dma_map_single(&pdev->dev, _elphel_buf.h2d_vaddr, (_elphel_buf.h2d_size*PAGE_SIZE), DMA_TO_DEVICE); if (!pElphel_buf->h2d_paddr){ if (!pElphel_buf->h2d_paddr){ printk("ERROR in dma_map_single() for bidirectional buffer"); pr_err("ERROR in dma_map_single() for bidirectional buffer\n"); return 0; return 0; } } // printk("H2D DMA buffer location:\t\t0x%08X\n", pElphel_buf->h2d_paddr); // printk("H2D DMA buffer location:\t\t0x%08X\n", pElphel_buf->h2d_paddr); Loading @@ -402,7 +405,7 @@ static int elphel393_mem_probe(struct platform_device *pdev) // mapped as DMA_BIDIRECTIONAL, each time will be synchronized when passing control from soft to hard and back // mapped as DMA_BIDIRECTIONAL, each time will be synchronized when passing control from soft to hard and back pElphel_buf->d2h_paddr = dma_map_single(&pdev->dev, _elphel_buf.d2h_vaddr, (_elphel_buf.d2h_size*PAGE_SIZE), DMA_FROM_DEVICE); pElphel_buf->d2h_paddr = dma_map_single(&pdev->dev, _elphel_buf.d2h_vaddr, (_elphel_buf.d2h_size*PAGE_SIZE), DMA_FROM_DEVICE); if (!pElphel_buf->d2h_paddr){ if (!pElphel_buf->d2h_paddr){ printk("ERROR in dma_map_single() for bidirectional buffer"); pr_err("ERROR in dma_map_single() for bidirectional buffer\n"); return 0; return 0; } } // printk("D2H DMA buffer location:\t\t0x%08X\n", pElphel_buf->d2h_paddr); // printk("D2H DMA buffer location:\t\t0x%08X\n", pElphel_buf->d2h_paddr); Loading @@ -413,7 +416,7 @@ static int elphel393_mem_probe(struct platform_device *pdev) // mapped as DMA_BIDIRECTIONAL, each time will be synchronized when passing control from soft to hard and back // mapped as DMA_BIDIRECTIONAL, each time will be synchronized when passing control from soft to hard and back pElphel_buf->bidir_paddr = dma_map_single(&pdev->dev, _elphel_buf.bidir_vaddr, (_elphel_buf.bidir_size*PAGE_SIZE), DMA_BIDIRECTIONAL); pElphel_buf->bidir_paddr = dma_map_single(&pdev->dev, _elphel_buf.bidir_vaddr, (_elphel_buf.bidir_size*PAGE_SIZE), DMA_BIDIRECTIONAL); if (!pElphel_buf->bidir_paddr){ if (!pElphel_buf->bidir_paddr){ printk("ERROR in dma_map_single() for bidirectional buffer"); pr_err("ERROR in dma_map_single() for bidirectional buffer\n"); return 0; return 0; } } // printk("Bidirectional DMA buffer location:\t0x%08X\n", pElphel_buf->bidir_paddr); // printk("Bidirectional DMA buffer location:\t0x%08X\n", pElphel_buf->bidir_paddr); Loading @@ -438,7 +441,7 @@ static int elphel393_mem_probe(struct platform_device *pdev) static int elphel393_mem_remove(struct platform_device *pdev) static int elphel393_mem_remove(struct platform_device *pdev) { { dev_info(&pdev->dev,"Removing elphel393-mem"); pr_info("Removing elphel393-mem"); return 0; return 0; } } Loading @@ -452,7 +455,7 @@ static struct platform_driver elphel393_mem = { .probe = elphel393_mem_probe, .probe = elphel393_mem_probe, .remove = elphel393_mem_remove, .remove = elphel393_mem_remove, .driver = { .driver = { .name = "elphel393-mem", .name = DRV_NAME, .owner = THIS_MODULE, .owner = THIS_MODULE, .of_match_table = elphel393_mem_of_match, .of_match_table = elphel393_mem_of_match, .pm = NULL, /* power management */ .pm = NULL, /* power management */ Loading @@ -463,5 +466,5 @@ module_platform_driver(elphel393_mem); module_init(elphelmem_init); module_init(elphelmem_init); module_exit(elphelmem_exit); module_exit(elphelmem_exit); MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Elphel, Inc."); MODULE_DESCRIPTION("Reserve a large chunk of contiguous memory at boot");
src/drivers/elphel/sensor_i2c.c +166 −31 Original line number Original line Diff line number Diff line Loading @@ -289,8 +289,8 @@ static ssize_t get_i2c_page_alloc(struct device *dev, struct device_attribute *a { { int chn = get_channel_from_name(attr) ; int chn = get_channel_from_name(attr) ; int page; int page; if (sysfs_page[chn]>=0) // if (sysfs_page[chn]>=0) return -EBUSY; // return -EBUSY; page= i2c_page_alloc(chn); page= i2c_page_alloc(chn); if (page <0) if (page <0) return -ENOMEM; return -ENOMEM; Loading @@ -303,17 +303,30 @@ static ssize_t free_i2c_page(struct device *dev, struct device_attribute *attr, int page; int page; sscanf(buf, "%i", &page); sscanf(buf, "%i", &page); page &= 0xff; page &= 0xff; if (sysfs_page[chn] >= 0) // if (sysfs_page[chn] >= 0) // i2c_page_free(chn, page); // sysfs_page[chn] = -1; // free i2c_page_free(chn, page); i2c_page_free(chn, page); sysfs_page[chn] = -1; // free return count; return count; } } /* Set/get page number for reading */ static ssize_t set_i2c_page_inuse(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int chn = get_channel_from_name(attr) ; int page; sscanf(buf, "%i", &page); sysfs_page[chn] = page & 0xff; return count; } static ssize_t get_i2c_page_inuse(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t get_i2c_page_inuse(struct device *dev, struct device_attribute *attr, char *buf) { { int chn = get_channel_from_name(attr) ; int chn = get_channel_from_name(attr) ; return sprintf(buf,"%d\n",sysfs_page[chn]); return sprintf(buf,"%d\n",sysfs_page[chn]); } } // Get i2c table data as raw data (hex) // Get i2c table data as raw data (hex) static ssize_t get_i2c_tbl_raw(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t get_i2c_tbl_raw(struct device *dev, struct device_attribute *attr, char *buf) { { Loading @@ -322,49 +335,170 @@ static ssize_t get_i2c_tbl_raw(struct device *dev, struct device_attribute *attr if (page < 0) if (page < 0) return -ENXIO; /* No such device or address */ return -ENXIO; /* No such device or address */ return sprintf(buf,"%0x08x\n",i2c_pages_shadow[(chn << 8) + (page &0xff)]); return sprintf(buf,"0x%08x\n",i2c_pages_shadow[(chn << 8) + (page &0xff)]); } } static ssize_t set_i2c_tbl_raw(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) static ssize_t set_i2c_tbl_raw(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { { int chn = get_channel_from_name(attr) ; int chn = get_channel_from_name(attr) ; int page, data; int ni, page, data; sscanf(buf, "%i %i", &page, &data); ni = sscanf(buf, "%i %i", &page, &data); page &= 0xff; if (ni < 2) dev_err(dev, "Requires 2 parameters: page, data\n"); return -EINVAL; set_sensor_i2c_raw(chn, set_sensor_i2c_raw(chn, page, // index in lookup table page & 0xff, // index in lookup table (u32) data); // Bit delay - number of mclk periods in 1/4 of the SCL period (u32) data); // Bit delay - number of mclk periods in 1/4 of the SCL period return count; return count; } } // Sysfs top // Get/parse i2c table (hex) static ssize_t get_i2c_tbl_human(struct device *dev, struct device_attribute *attr, char *buf) { x393_i2c_ctltbl_t tb_data; int chn = get_channel_from_name(attr) ; int page = sysfs_page[chn]; // currently selected page for sysfs reads if (page < 0) return -ENXIO; /* No such device or address */ tb_data.d32 = i2c_pages_shadow[(chn << 8) + (page &0xff)]; if (tb_data.rnw){ return sprintf(buf,"Read entry: chn=%d page=%d(0x%x) two_byte_addr=%d number bytes to read=%d bit_duration=%d\n", chn, page,page, tb_data.nabrd,tb_data.nabrd,tb_data.nbrd, tb_data.dly); } else { return sprintf(buf,"Write entry: chn=%d page=%d(0x%x) sa=0x%02x rah=0x%02x nbw=%d bit_duration=%d\n", chn, page,page,tb_data.sa,tb_data.rah,tb_data.nbwr, tb_data.dly); } } static ssize_t set_i2c_tbl_wr_human(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int chn = get_channel_from_name(attr) ; int ni, page, rah,sa7,nbwr,dly; ni = sscanf(buf, "%i %i %i %i %i", &page, &sa7, &rah, &nbwr, &dly); if (ni < 2) dev_err(dev, "Requires 5 parameters: page, slave address (7 bit), high reg address byte, bytes to write (1..10), 1/4 scl period in mclk\n"); return -EINVAL; set_sensor_i2c_wr(chn, page & 0xff, // index in lookup table sa7 & 0x7f, // slave address (7 bit) rah & 0xff, // High byte of the i2c register address nbwr & 0xf, // Number of bytes to write (1..10) dly & 0xff); // Bit delay - number of mclk periods in 1/4 of the SCL period return count; } static DEVICE_ATTR(alloc0 , SYSFS_PERMISSIONS & SYSFS_READONLY, get_i2c_page_alloc , NULL); static ssize_t set_i2c_tbl_rd_human(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) static DEVICE_ATTR(alloc1 , SYSFS_PERMISSIONS & SYSFS_READONLY, get_i2c_page_alloc , NULL); { static DEVICE_ATTR(alloc2 , SYSFS_PERMISSIONS & SYSFS_READONLY, get_i2c_page_alloc , NULL); int chn = get_channel_from_name(attr) ; static DEVICE_ATTR(alloc3 , SYSFS_PERMISSIONS & SYSFS_READONLY, get_i2c_page_alloc , NULL); int ni, page, two_byte_addr, num_bytes,bit_delay; static DEVICE_ATTR(page_in_use0 , SYSFS_PERMISSIONS , get_i2c_page_inuse, free_i2c_page); ni = sscanf(buf, "%i %i %i %i %i", &page, &two_byte_addr, &num_bytes, &bit_delay); static DEVICE_ATTR(page_in_use1 , SYSFS_PERMISSIONS , get_i2c_page_inuse, free_i2c_page); if (ni < 2) static DEVICE_ATTR(page_in_use2 , SYSFS_PERMISSIONS , get_i2c_page_inuse, free_i2c_page); dev_err(dev, "Requires 4 parameters: page, two byte addr (0 - 8bit,1 - 16 bit reg. addr), number of bytes to read, bytes to write (1..10), 1/4 scl period in mclk\n"); static DEVICE_ATTR(page_in_use3 , SYSFS_PERMISSIONS , get_i2c_page_inuse, free_i2c_page); return -EINVAL; set_sensor_i2c_rd( chn, page & 0xff, // index in lookup table two_byte_addr & 1, // Number of address bytes (0 - one byte, 1 - two bytes) num_bytes & 7, // Number of bytes to read (1..8, 0 means 8) bit_delay & 0xff); // Bit delay - number of mclk periods in 1/4 of the SCL period return count; } static ssize_t set_i2c_read(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int chn = get_channel_from_name(attr) ; int ni, page, sa7, addr; ni = sscanf(buf, "%i %i %i", &page, &sa7, addr); if (ni <3) dev_err(dev, "Requires 3 parameters: page, sa7, reg_addr\n"); return -EINVAL; page &= 0xff; read_sensor_i2c (chn, page & 0xff, // page (8 bits) sa7 & 0x7f, // 7-bit i2c slave address addr & 0xffff); // 8/16 bit address return count; } // Get i2c read data from fifo static ssize_t get_i2c_read(struct device *dev, struct device_attribute *attr, char *buf) { int chn = get_channel_from_name(attr) ; int page = sysfs_page[chn]; // currently selected page for sysfs reads if (page < 0) return -ENXIO; /* No such device or address */ return sprintf(buf,"%d\n",read_sensor_i2c_fifo(chn)); // <0 - not ready, 0..255 - data } // Get i2c read data from fifo static ssize_t get_i2c_help(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf,"Numeric suffix in file names selects sensor port\n" "alloc*: read - allocate and return page, write <page> (any data) - free page\n" "rd_page*: read/write page number used in read operations (-1 if none)\n" "tbl_raw*: read - raw hex table value (for current rd_page), write <page> <data32> set page\n" "tbl_wr*: read - decoded table entry for current rd_page, write <page> <sa7> <high_addr_byte> <bytes_to_write> <dly>\n" "tbl_rd*: read - decoded table entry for current rd_page, write <page> <2-byte addr> <bytes_to_read> <dly>\n" "tbl_rd* and tbl_wr* return same result when read. Delay is 8 bit, 250 - 200KHz SCL\n"); } // Sysfs top /* alloc*: read - allocate and return page, write (any data) - free page */ static DEVICE_ATTR(alloc0 , SYSFS_PERMISSIONS , get_i2c_page_alloc , free_i2c_page); static DEVICE_ATTR(alloc1 , SYSFS_PERMISSIONS , get_i2c_page_alloc , free_i2c_page); static DEVICE_ATTR(alloc2 , SYSFS_PERMISSIONS , get_i2c_page_alloc , free_i2c_page); static DEVICE_ATTR(alloc3 , SYSFS_PERMISSIONS , get_i2c_page_alloc , free_i2c_page); /* rd_page*: read/write page number used in read operations */ static DEVICE_ATTR(rd_page0 , SYSFS_PERMISSIONS , get_i2c_page_inuse, set_i2c_page_inuse); static DEVICE_ATTR(rd_page1 , SYSFS_PERMISSIONS , get_i2c_page_inuse, set_i2c_page_inuse); static DEVICE_ATTR(rd_page2 , SYSFS_PERMISSIONS , get_i2c_page_inuse, set_i2c_page_inuse); static DEVICE_ATTR(rd_page3 , SYSFS_PERMISSIONS , get_i2c_page_inuse, set_i2c_page_inuse); static DEVICE_ATTR(tbl_raw0 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw); static DEVICE_ATTR(tbl_raw0 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw); static DEVICE_ATTR(tbl_raw1 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw); static DEVICE_ATTR(tbl_raw1 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw); static DEVICE_ATTR(tbl_raw2 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw); static DEVICE_ATTR(tbl_raw2 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw); static DEVICE_ATTR(tbl_raw3 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw); static DEVICE_ATTR(tbl_raw3 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw); static DEVICE_ATTR(tbl_wr0 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_wr_human); static DEVICE_ATTR(tbl_wr1 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_wr_human); static DEVICE_ATTR(tbl_wr2 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_wr_human); static DEVICE_ATTR(tbl_wr3 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_wr_human); static DEVICE_ATTR(tbl_rd0 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_rd_human); static DEVICE_ATTR(tbl_rd1 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_rd_human); static DEVICE_ATTR(tbl_rd2 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_rd_human); static DEVICE_ATTR(tbl_rd3 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_rd_human); static DEVICE_ATTR(i2c_rd0 , SYSFS_PERMISSIONS , get_i2c_read, set_i2c_read); static DEVICE_ATTR(i2c_rd1 , SYSFS_PERMISSIONS , get_i2c_read, set_i2c_read); static DEVICE_ATTR(i2c_rd2 , SYSFS_PERMISSIONS , get_i2c_read, set_i2c_read); static DEVICE_ATTR(i2c_rd3 , SYSFS_PERMISSIONS , get_i2c_read, set_i2c_read); static DEVICE_ATTR(help, SYSFS_PERMISSIONS & SYSFS_READONLY, get_i2c_help, NULL); static struct attribute *root_dev_attrs[] = { static struct attribute *root_dev_attrs[] = { &dev_attr_alloc0.attr, &dev_attr_alloc0.attr, &dev_attr_alloc1.attr, &dev_attr_alloc1.attr, &dev_attr_alloc2.attr, &dev_attr_alloc2.attr, &dev_attr_alloc3.attr, &dev_attr_alloc3.attr, &dev_attr_page_in_use0.attr, &dev_attr_rd_page0.attr, &dev_attr_page_in_use1.attr, &dev_attr_rd_page1.attr, &dev_attr_page_in_use2.attr, &dev_attr_rd_page2.attr, &dev_attr_page_in_use3.attr, &dev_attr_rd_page3.attr, &dev_attr_tbl_raw0.attr, &dev_attr_tbl_raw0.attr, &dev_attr_tbl_raw1.attr, &dev_attr_tbl_raw1.attr, &dev_attr_tbl_raw2.attr, &dev_attr_tbl_raw2.attr, &dev_attr_tbl_raw3.attr, &dev_attr_tbl_raw3.attr, &dev_attr_tbl_wr0.attr, &dev_attr_tbl_wr1.attr, &dev_attr_tbl_wr2.attr, &dev_attr_tbl_wr3.attr, &dev_attr_tbl_rd0.attr, &dev_attr_tbl_rd1.attr, &dev_attr_tbl_rd2.attr, &dev_attr_tbl_rd3.attr, &dev_attr_i2c_rd0.attr, &dev_attr_i2c_rd1.attr, &dev_attr_i2c_rd2.attr, &dev_attr_i2c_rd3.attr, &dev_attr_help.attr, NULL NULL }; }; Loading Loading @@ -412,13 +546,14 @@ static int elphel393_sensor_i2c_probe(struct platform_device *pdev) struct i2c_client *ltc3589_client; struct i2c_client *ltc3589_client; struct elphel393_pwr_data_t *clientdata = NULL; struct elphel393_pwr_data_t *clientdata = NULL; */ */ dev_info(&pdev->dev,"Probing elphel393-sensor-i2c\n"); pr_info("Probing elphel393-sensor-i2c\n"); elphel393_sens_i2c_sysfs_register(pdev); i2c_page_alloc_init(); i2c_page_alloc_init(); #if 0 #if 0 clientdata = devm_kzalloc(&pdev->dev, sizeof(*clientdata), GFP_KERNEL); clientdata = devm_kzalloc(&pdev->dev, sizeof(*clientdata), GFP_KERNEL); #endif #endif elphel393_sensor_i2c_init_of(pdev); elphel393_sensor_i2c_init_of(pdev); elphel393_sens_i2c_sysfs_register(pdev); pr_info("done probing elphel393-sensor-i2c\n"); return 0; return 0; } } Loading @@ -435,7 +570,7 @@ static struct of_device_id elphel393_sensor_i2c_of_match[] = { MODULE_DEVICE_TABLE(of, elphel393_sensor_i2c_of_match); MODULE_DEVICE_TABLE(of, elphel393_sensor_i2c_of_match); static struct platform_driver elphel393_pwr = { static struct platform_driver elphel393_sensor_i2c = { .probe = elphel393_sensor_i2c_probe, .probe = elphel393_sensor_i2c_probe, .remove = elphel393_sensor_i2c_remove, .remove = elphel393_sensor_i2c_remove, .driver = { .driver = { Loading @@ -446,7 +581,7 @@ static struct platform_driver elphel393_pwr = { }, }, }; }; module_platform_driver(elphel393_pwr); module_platform_driver(elphel393_sensor_i2c); MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>"); MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>"); MODULE_DESCRIPTION("Elphel 10393 sensor ports i2c"); MODULE_DESCRIPTION("Elphel 10393 sensor ports i2c"); Loading