Commit 7dc7967f authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

staging: kpc2000: add initial set of Daktronics drivers

These drivers have been outside of the kernel tree since the 2.x days,
and it's time to bring them into the tree so they can get properly
cleaned up.

This first dump of drivers is based on a tarball Matt gave to me, minus
an odd "dma" driver that I could not get to build at all.  I renamed a
few files, added the proper SPDX lines to it, added Kconfig entries and
tied it into the kernel build.  I also fixed up a number of initial
obvious kernel build warnings, but left the odd bitfield warning that
gcc is spitting out, as I'm not quite sure what to do about that.

There's loads of low-hanging coding style cleanups in here for people to
start attacking, as well as the more obvious logic and api cleanups as
well.

Cc: Matt Sickler <Matt.Sickler@daktronics.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent f59232a1
...@@ -122,4 +122,6 @@ source "drivers/staging/erofs/Kconfig" ...@@ -122,4 +122,6 @@ source "drivers/staging/erofs/Kconfig"
source "drivers/staging/fieldbus/Kconfig" source "drivers/staging/fieldbus/Kconfig"
source "drivers/staging/kpc2000/Kconfig"
endif # STAGING endif # STAGING
...@@ -51,3 +51,4 @@ obj-$(CONFIG_STAGING_GASKET_FRAMEWORK) += gasket/ ...@@ -51,3 +51,4 @@ obj-$(CONFIG_STAGING_GASKET_FRAMEWORK) += gasket/
obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/ obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/
obj-$(CONFIG_EROFS_FS) += erofs/ obj-$(CONFIG_EROFS_FS) += erofs/
obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/ obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/
obj-$(CONFIG_KPC2000) += kpc2000/
# SPDX-License-Identifier: GPL-2.0
config KPC2000
bool "Daktronics KPC Device support"
depends on PCI
help
Select this if you wish to use the Daktronics KPC PCI devices
If unsure, say N.
config KPC2000_CORE
tristate "Daktronics KPC PCI UIO device"
depends on KPC2000
help
Say Y here if you wish to support the Daktronics KPC PCI
device in UIO mode.
To compile this driver as a module, choose M here: the module
will be called kpc2000
If unsure, say N.
config KPC2000_SPI
tristate "Kaktronics KPC SPI device"
depends on KPC2000 && SPI
help
Say Y here if you wish to support the Daktronics KPC PCI
device in SPI mode.
To compile this driver as a module, choose M here: the module
will be called kpc2000_spi
If unsure, say N.
config KPC2000_I2C
tristate "Kaktronics KPC I2C device"
depends on KPC2000 && I2C
help
Say Y here if you wish to support the Daktronics KPC PCI
device in I2C mode.
To compile this driver as a module, choose M here: the module
will be called kpc2000_i2c
If unsure, say N.
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_KPC2000) += kpc2000/
obj-$(CONFIG_KPC2000_I2C) += kpc_i2c/
obj-$(CONFIG_KPC2000_SPI) += kpc_spi/
- the kpc_spi driver doesn't seem to let multiple transactions (to different instances of the core) happen in parallel...
- The kpc_i2c driver is a hot mess, it should probably be cleaned up a ton. It functions against current hardware though.
- pcard->card_num in kp2000_pcie_probe() is a global variable and needs atomic / locking / something better.
- probe_core_uio() probably needs error handling
- the loop in kp2000_probe_cores() that uses probe_core_uio() also probably needs error handling
- would be nice if the AIO fileops in kpc_dma could be made to work
- probably want to add a CONFIG_ option to control compilation of the AIO functions
- if the AIO fileops in kpc_dma start working, next would be making iov_count > 1 work too
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef KPC_H_
#define KPC_H_
/* ***** Driver Names ***** */
#define KP_DRIVER_NAME_KP2000 "kp2000"
#define KP_DRIVER_NAME_INVALID "kpc_invalid"
#define KP_DRIVER_NAME_DMA_CONTROLLER "kpc_nwl_dma"
#define KP_DRIVER_NAME_UIO "uio_pdrv_genirq"
#define KP_DRIVER_NAME_I2C "kpc_i2c"
#define KP_DRIVER_NAME_SPI "kpc_spi"
struct kpc_core_device_platdata {
u32 card_id;
u32 build_version;
u32 hardware_revision;
u64 ssid;
u64 ddna;
};
#define PCI_DEVICE_ID_DAKTRONICS_KADOKA_P2KR0 0x4b03
#endif /* KPC_H_ */
# SPDX-License-Identifier: GPL-2.0
obj-m := kpc2000.o
kpc2000-objs += kp2000_module.o core.o cell_probe.o fileops.o
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef KPC_DMA_COMMON_DEFS_H_
#define KPC_DMA_COMMON_DEFS_H_
#define KPC_DMA_COMMON_OFFSET 0x4000
#define KPC_DMA_S2C_BASE_OFFSET 0x0000
#define KPC_DMA_C2S_BASE_OFFSET 0x2000
#define KPC_DMA_ENGINE_SIZE 0x0100
#define ENGINE_CAP_PRESENT_MASK 0x1
#define KPC_DMA_CARD_IRQ_ENABLE (1 << 0)
#define KPC_DMA_CARD_IRQ_ACTIVE (1 << 1)
#define KPC_DMA_CARD_IRQ_PENDING (1 << 2)
#define KPC_DMA_CARD_IRQ_MSI (1 << 3)
#define KPC_DMA_CARD_USER_INTERRUPT_MODE (1 << 4)
#define KPC_DMA_CARD_USER_INTERRUPT_ACTIVE (1 << 5)
#define KPC_DMA_CARD_IRQ_MSIX_MODE (1 << 6)
#define KPC_DMA_CARD_MAX_PAYLOAD_SIZE_MASK 0x0700
#define KPC_DMA_CARD_MAX_READ_REQUEST_SIZE_MASK 0x7000
#define KPC_DMA_CARD_S2C_INTERRUPT_STATUS_MASK 0x00FF0000
#define KPC_DMA_CARD_C2S_INTERRUPT_STATUS_MASK 0xFF000000
static inline void SetBackEndControl(void __iomem *regs, u32 value)
{
writel(value, regs + 0);
}
static inline u32 GetBackEndStatus(void __iomem *regs)
{
return readl(regs + 0);
}
static inline u32 BackEndControlSetClear(void __iomem *regs, u32 set_bits, u32 clear_bits)
{
u32 start_val = GetBackEndStatus(regs);
u32 new_val = start_val;
new_val &= ~clear_bits;
new_val |= set_bits;
SetBackEndControl(regs, new_val);
return start_val;
}
#endif /* KPC_DMA_COMMON_DEFS_H_ */
// SPDX-License-Identifier: GPL-2.0+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/cdev.h>
#include <linux/uaccess.h> /* copy_*_user */
#include <linux/rwsem.h>
#include <linux/idr.h>
#include <linux/device.h>
#include <linux/sched.h>
#include "pcie.h"
#include "uapi.h"
int kp2000_cdev_open(struct inode *inode, struct file *filp)
{
struct kp2000_device *pcard = container_of(filp->private_data, struct kp2000_device, miscdev);
dev_dbg(&pcard->pdev->dev, "kp2000_cdev_open(filp = [%p], pcard = [%p])\n", filp, pcard);
filp->private_data = pcard; /* so other methods can access it */
return 0;
}
int kp2000_cdev_close(struct inode *inode, struct file *filp)
{
struct kp2000_device *pcard = filp->private_data;
dev_dbg(&pcard->pdev->dev, "kp2000_cdev_close(filp = [%p], pcard = [%p])\n", filp, pcard);
return 0;
}
ssize_t kp2000_cdev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
struct kp2000_device *pcard = filp->private_data;
int cnt = 0;
int ret;
#define BUFF_CNT 1024
char buff[BUFF_CNT] = {0}; //NOTE: Increase this so it is at least as large as all the scnprintfs. And don't use unbounded strings. "%s"
//NOTE: also, this is a really shitty way to implement the read() call, but it will work for any size 'count'.
if (WARN(NULL == buf, "kp2000_cdev_read: buf is a NULL pointer!\n"))
return -EINVAL;
cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Card ID : 0x%08x\n", pcard->card_id);
cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Build Version : 0x%08x\n", pcard->build_version);
cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Build Date : 0x%08x\n", pcard->build_datestamp);
cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Build Time : 0x%08x\n", pcard->build_timestamp);
cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Core Table Offset : 0x%08x\n", pcard->core_table_offset);
cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Core Table Length : 0x%08x\n", pcard->core_table_length);
cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Hardware Revision : 0x%08x\n", pcard->hardware_revision);
cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "SSID : 0x%016llx\n", pcard->ssid);
cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "DDNA : 0x%016llx\n", pcard->ddna);
cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "IRQ Mask : 0x%016llx\n", readq(pcard->sysinfo_regs_base + REG_INTERRUPT_MASK));
cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "IRQ Active : 0x%016llx\n", readq(pcard->sysinfo_regs_base + REG_INTERRUPT_ACTIVE));
cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "CPLD : 0x%016llx\n", readq(pcard->sysinfo_regs_base + REG_CPLD_CONFIG));
if (*f_pos >= cnt)
return 0;
if (count > cnt)
count = cnt;
ret = copy_to_user(buf, buff + *f_pos, count);
if (ret)
return -EFAULT;
*f_pos += count;
return count;
}
ssize_t kp2000_cdev_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
return -EINVAL;
}
long kp2000_cdev_ioctl(struct file *filp, unsigned int ioctl_num, unsigned long ioctl_param)
{
struct kp2000_device *pcard = filp->private_data;
dev_dbg(&pcard->pdev->dev, "kp2000_cdev_ioctl(filp = [%p], ioctl_num = 0x%08x, ioctl_param = 0x%016lx) pcard = [%p]\n", filp, ioctl_num, ioctl_param, pcard);
switch (ioctl_num){
case KP2000_IOCTL_GET_CPLD_REG: return readq(pcard->sysinfo_regs_base + REG_CPLD_CONFIG);
case KP2000_IOCTL_GET_PCIE_ERROR_REG: return readq(pcard->sysinfo_regs_base + REG_PCIE_ERROR_COUNT);
case KP2000_IOCTL_GET_EVERYTHING: {
struct kp2000_regs temp;
int ret;
temp.card_id = pcard->card_id;
temp.build_version = pcard->build_version;
temp.build_datestamp = pcard->build_datestamp;
temp.build_timestamp = pcard->build_timestamp;
temp.hw_rev = pcard->hardware_revision;
temp.ssid = pcard->ssid;
temp.ddna = pcard->ddna;
temp.cpld_reg = readq(pcard->sysinfo_regs_base + REG_CPLD_CONFIG);
ret = copy_to_user((void*)ioctl_param, (void*)&temp, sizeof(temp));
if (ret)
return -EFAULT;
return sizeof(temp);
}
default:
return -ENOTTY;
}
return -ENOTTY;
}
struct file_operations kp2000_fops = {
.owner = THIS_MODULE,
.open = kp2000_cdev_open,
.release = kp2000_cdev_close,
.read = kp2000_cdev_read,
//.write = kp2000_cdev_write,
//.poll = kp2000_cdev_poll,
//.fasync = kp2000_cdev_fasync,
.llseek = noop_llseek,
.unlocked_ioctl = kp2000_cdev_ioctl,
};
// SPDX-License-Identifier: GPL-2.0+
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/types.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <linux/io.h>
#include <linux/mfd/core.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include "pcie.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Lee.Brooke@Daktronics.com, Matt.Sickler@Daktronics.com");
MODULE_SOFTDEP("pre: uio post: kpc_nwl_dma kpc_i2c kpc_spi");
struct class *kpc_uio_class;
ATTRIBUTE_GROUPS(kpc_uio_class);
static const struct pci_device_id kp2000_pci_device_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_DAKTRONICS, PCI_DEVICE_ID_DAKTRONICS) },
{ PCI_DEVICE(PCI_VENDOR_ID_DAKTRONICS, PCI_DEVICE_ID_DAKTRONICS_KADOKA_P2KR0) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, kp2000_pci_device_ids);
static struct pci_driver kp2000_driver_inst = {
.name = "kp2000_pcie",
.id_table = kp2000_pci_device_ids,
.probe = kp2000_pcie_probe,
.remove = kp2000_pcie_remove
};
static int __init kp2000_pcie_init(void)
{
kpc_uio_class = class_create(THIS_MODULE, "kpc_uio");
if (IS_ERR(kpc_uio_class))
return PTR_ERR(kpc_uio_class);
kpc_uio_class->dev_groups = kpc_uio_class_groups;
return pci_register_driver(&kp2000_driver_inst);
}
module_init(kp2000_pcie_init);
static void __exit kp2000_pcie_exit(void)
{
pci_unregister_driver(&kp2000_driver_inst);
class_destroy(kpc_uio_class);
}
module_exit(kp2000_pcie_exit);
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef KP2000_PCIE_H
#define KP2000_PCIE_H
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/pci.h>
#include "../kpc.h"
#include "dma_common_defs.h"
/* System Register Map (BAR 1, Start Addr 0)
*
* BAR Size:
* 1048576 (0x100000) bytes = 131072 (0x20000) registers = 256 pages (4K)
*
* 6 5 4 3 2 1 0
* 3210987654321098765432109876543210987654321098765432109876543210
* 0 <--------------------------- MAGIC ---------------------------->
* 1 <----------- Card ID ---------><----------- Revision ---------->
* 2 <--------- Date Stamp --------><--------- Time Stamp ---------->
* 3 <-------- Core Tbl Len -------><-------- Core Tbl Offset ------>
* 4 <---------------------------- SSID ---------------------------->
* 5 < HWID >
* 6 <------------------------- FPGA DDNA -------------------------->
* 7 <------------------------ CPLD Config ------------------------->
* 8 <----------------------- IRQ Mask Flags ----------------------->
* 9 <---------------------- IRQ Active Flags ---------------------->
*/
#define REG_WIDTH 8
#define REG_MAGIC_NUMBER (0 * REG_WIDTH)
#define REG_CARD_ID_AND_BUILD (1 * REG_WIDTH)
#define REG_DATE_AND_TIME_STAMPS (2 * REG_WIDTH)
#define REG_CORE_TABLE_OFFSET (3 * REG_WIDTH)
#define REG_FPGA_SSID (4 * REG_WIDTH)
#define REG_FPGA_HW_ID (5 * REG_WIDTH)
#define REG_FPGA_DDNA (6 * REG_WIDTH)
#define REG_CPLD_CONFIG (7 * REG_WIDTH)
#define REG_INTERRUPT_MASK (8 * REG_WIDTH)
#define REG_INTERRUPT_ACTIVE (9 * REG_WIDTH)
#define REG_PCIE_ERROR_COUNT (10 * REG_WIDTH)
#define KP2000_MAGIC_VALUE 0x196C61482231894D
#define PCI_VENDOR_ID_DAKTRONICS 0x1c33
#define PCI_DEVICE_ID_DAKTRONICS 0x6021
#define DMA_BAR 0
#define REG_BAR 1
struct kp2000_device {
struct pci_dev *pdev;
struct miscdevice miscdev;
char name[16];
unsigned int card_num;
struct mutex sem;
void __iomem *sysinfo_regs_base;
void __iomem *regs_bar_base;
struct resource regs_base_resource;
void __iomem *dma_bar_base;
void __iomem *dma_common_regs;
struct resource dma_base_resource;
// "System Registers"
u32 card_id;
u32 build_version;
u32 build_datestamp;
u32 build_timestamp;
u32 core_table_offset;
u32 core_table_length;
u8 core_table_rev;
u8 hardware_revision;
u64 ssid;
u64 ddna;
// IRQ stuff
unsigned int irq;
struct list_head uio_devices_list;
};
extern struct class *kpc_uio_class;
extern struct attribute *kpc_uio_class_attrs[];
int kp2000_pcie_probe(struct pci_dev *dev, const struct pci_device_id *id);
void kp2000_pcie_remove(struct pci_dev *pdev);
int kp2000_probe_cores(struct kp2000_device *pcard);
void kp2000_remove_cores(struct kp2000_device *pcard);
extern struct file_operations kp2000_fops;
// Define this quick little macro because the expression is used frequently
#define PCARD_TO_DEV(pcard) (&(pcard->pdev->dev))
static inline void
lock_card(struct kp2000_device *pcard)
{
BUG_ON(pcard == NULL);
mutex_lock(&pcard->sem);
}
static inline void
unlock_card(struct kp2000_device *pcard)
{
BUG_ON(pcard == NULL);
mutex_unlock(&pcard->sem);
}
#endif /* KP2000_PCIE_H */
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef KP2000_CDEV_UAPI_H_
#define KP2000_CDEV_UAPI_H_
#include <linux/types.h>
#include <linux/ioctl.h>
struct kp2000_regs {
__u32 card_id;
__u32 build_version;
__u32 build_datestamp;
__u32 build_timestamp;
__u32 hw_rev;
__u64 ssid;
__u64 ddna;
__u64 cpld_reg;
};
#define KP2000_IOCTL_GET_CPLD_REG _IOR('k', 9, __u32)
#define KP2000_IOCTL_GET_PCIE_ERROR_REG _IOR('k', 11, __u32)
#define KP2000_IOCTL_GET_EVERYTHING _IOR('k', 8, struct kp2000_regs*)
#endif /* KP2000_CDEV_UAPI_H_ */
# SPDX-License-Identifier: GPL-2.0
obj-m := kpc2000_i2c.o
kpc2000_i2c-objs := i2c_driver.o fileops.o
// SPDX-License-Identifier: GPL-2.0+
#if 0
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/cdev.h>
#include <asm/uaccess.h> /* copy_*_user */
#include "i2c_driver.h"
int i2c_cdev_open(struct inode *inode, struct file *filp)
{
struct i2c_device *lddev;
if(NULL == inode) {
//printk(KERN_WARNING "<pl_i2c> i2c_cdev_open: inode is a NULL pointer\n");
DBG_PRINT(KERN_WARNING, "i2c_cdev_open: inode is a NULL pointer\n");
return -EINVAL;
}
if(NULL == filp) {
//printk(KERN_WARNING "<pl_i2c> i2c_cdev_open: filp is a NULL pointer\n");
DBG_PRINT(KERN_WARNING, "i2c_cdev_open: filp is a NULL pointer\n");
return -EINVAL;
}
lddev = container_of(inode->i_cdev, struct i2c_device, cdev);
//printk(KERN_DEBUG "<pl_i2c> i2c_cdev_open(filp = [%p], lddev = [%p])\n", filp, lddev);
DBG_PRINT(KERN_DEBUG, "i2c_cdev_open(filp = [%p], lddev = [%p])\n", filp, lddev);
filp->private_data = lddev; /* so other methods can access it */
return 0; /* success */
}
int i2c_cdev_close(struct inode *inode, struct file *filp)
{
struct i2c_device *lddev;
if(NULL == inode) {
//printk(KERN_WARNING "<pl_i2c> i2c_cdev_close: inode is a NULL pointer\n");
DBG_PRINT(KERN_WARNING, "i2c_cdev_close: inode is a NULL pointer\n");
return -EINVAL;
}
if(NULL == filp) {
//printk(KERN_WARNING "<pl_i2c> i2c_cdev_close: filp is a NULL pointer\n");
DBG_PRINT(KERN_WARNING, "i2c_cdev_close: filp is a NULL pointer\n");
return -EINVAL;
}
lddev = filp->private_data;
//printk(KERN_DEBUG "<pl_i2c> i2c_cdev_close(filp = [%p], lddev = [%p])\n", filp, lddev);
DBG_PRINT(KERN_DEBUG, "i2c_cdev_close(filp = [%p], lddev = [%p])\n", filp, lddev);
return 0;
}
ssize_t i2c_cdev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
size_t copy;
ssize_t ret = 0;
int err = 0;
u64 read_val;
char tmp_buf[48] = { 0 };
struct i2c_device *lddev = filp->private_data;
if(NULL == filp) {
//printk(KERN_WARNING "<pl_i2c> i2c_cdev_read: filp is a NULL pointer\n");
DBG_PRINT(KERN_WARNING, "i2c_cdev_read: filp is a NULL pointer\n");
return -EINVAL;
}
if(NULL == buf) {
//printk(KERN_WARNING "<pl_i2c> i2c_cdev_read: buf is a NULL pointer\n");
DBG_PRINT(KERN_WARNING, "i2c_cdev_read: buf is a NULL pointer\n");
return -EINVAL;
}
if(NULL == f_pos) {
//printk(KERN_WARNING "<pl_i2c> i2c_cdev_read: f_pos is a NULL pointer\n");
DBG_PRINT(KERN_WARNING, "i2c_cdev_read: f_pos is a NULL pointer\n");
return -EINVAL;
}
if(count < sizeof(tmp_buf)) {
//printk(KERN_INFO "<pl_i2c> i2c_cdev_read: buffer is too small (count = %d, should be at least %d bytes)\n", (int)count, (int)sizeof(tmp_buf));
DBG_PRINT(KERN_INFO, "i2c_cdev_read: buffer is too small (count = %d, should be at least %d bytes)\n", (int)count, (int)sizeof(tmp_buf));
return -EINVAL;
}
if(((*f_pos * 8) + lddev->pldev->resource[0].start) > lddev->pldev->resource[0].end) {
//printk(KERN_INFO "<pl_i2c> i2c_cdev_read: bad read addr %016llx\n", (*f_pos * 8) + lddev->pldev->resource[0].start);
DBG_PRINT(KERN_INFO, "i2c_cdev_read: bad read addr %016llx\n", (*f_pos * 8) + lddev->pldev->resource[0].start);
//printk(KERN_INFO "<pl_i2c> i2c_cdev_read: addr end %016llx\n", lddev->pldev->resource[0].end);
DBG_PRINT(KERN_INFO, "i2c_cdev_read: addr end %016llx\n", lddev->pldev->resource[0].end);
//printk(KERN_INFO "<pl_i2c> i2c_cdev_read: EOF reached\n");
DBG_PRINT(KERN_INFO, "i2c_cdev_read: EOF reached\n");
return 0;
}
down_read(&lddev->rw_sem);
read_val = *(lddev->regs + *f_pos);
copy = clamp_t(size_t, count, 1, sizeof(tmp_buf));
copy = scnprintf(tmp_buf, copy, "reg: 0x%x val: 0x%llx\n", (unsigned int)*f_pos, read_val);
err = copy_to_user(buf, tmp_buf, copy);
if(err) {
//printk(KERN_INFO "<pl_i2c> i2c_cdev_read: could not copy to user (err = %d)\n", err);
DBG_PRINT(KERN_INFO, "i2c_cdev_read: could not copy to user (err = %d)\n", err);
return -EINVAL;
}
ret = (ssize_t)copy;
(*f_pos)++;
up_read(&lddev->rw_sem);
return ret;
}
ssize_t i2c_cdev_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
u8 reg;
u8 val;
char tmp[8] = { 0 };
struct i2c_device *lddev = filp->private_data;
if(NULL == filp) {
//printk(KERN_WARNING "<pl_i2c> i2c_cdev_write: filp is a NULL pointer\n");
DBG_PRINT(KERN_WARNING, "i2c_cdev_write: filp is a NULL pointer\n");
return -EINVAL;
}
if(NULL == buf) {
//printk(KERN_WARNING "<pl_i2c> i2c_cdev_write: buf is a NULL pointer\n");
DBG_PRINT(KERN_WARNING, "i2c_cdev_write: buf is a NULL pointer\n");
return -EINVAL;
}
if(NULL == f_pos) {
//printk(KERN_WARNING "<pl_i2c> i2c_cdev_write: f_pos is a NULL pointer\n");
DBG_PRINT(KERN_WARNING, "i2c_cdev_write: f_pos is a NULL pointer\n");
return -EINVAL;
}
//printk(KERN_DEBUG "<pl_i2c> i2c_cdev_write(filp = [%p], lddev = [%p])\n", filp, lddev);
DBG_PRINT(KERN_DEBUG, "i2c_cdev_write(filp = [%p], lddev = [%p])\n", filp, lddev);
down_write(&lddev->rw_sem);
if(count >= 2) {
if(copy_from_user(tmp, buf, 2)) {
return -EFAULT;
}
reg = tmp[0] - '0';
val = tmp[1] - '0';
//printk(KERN_DEBUG " reg = %d val = %d\n", reg, val);
DBG_PRINT(KERN_DEBUG, " reg = %d val = %d\n", reg, val);
if(reg >= 0 && reg < 16) {
//printk(KERN_DEBUG " Writing 0x%x to %p\n", val, lddev->regs + reg);
DBG_PRINT(KERN_DEBUG, " Writing 0x%x to %p\n", val, lddev->regs + reg);
*(lddev->regs + reg) = val;
}
}
(*f_pos)++;
up_write(&lddev->rw_sem);
return count;
}
struct file_operations i2c_fops = {
.owner = THIS_MODULE,
.open = i2c_cdev_open,
.release = i2c_cdev_close,
.read = i2c_cdev_read,
.write = i2c_cdev_write,
};
#endif
This diff is collapsed.
# SPDX-License-Identifier: GPL-2.0
obj-m += kpc2000_spi.o
kpc2000_spi-objs := spi_driver.o
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __KPC_SPI_SPI_PARTS_H__
#define __KPC_SPI_SPI_PARTS_H__
static struct mtd_partition p2kr0_spi0_parts[] = {
{ .name = "SLOT_0", .size = 7798784, .offset = 0, },
{ .name = "SLOT_1", .size = 7798784, .offset = MTDPART_OFS_NXTBLK },
{ .name = "SLOT_2", .size = 7798784, .offset = MTDPART_OFS_NXTBLK },
{ .name = "SLOT_3", .size = 7798784, .offset = MTDPART_OFS_NXTBLK },
{ .name = "CS0_EXTRA", .size = MTDPART_SIZ_FULL, .offset = MTDPART_OFS_NXTBLK }
};
static struct mtd_partition p2kr0_spi1_parts[] = {
{ .name = "SLOT_4", .size = 7798784, .offset = 0, },
{ .name = "SLOT_5", .size = 7798784, .offset = MTDPART_OFS_NXTBLK },
{ .name = "SLOT_6", .size = 7798784, .offset = MTDPART_OFS_NXTBLK },
{ .name = "SLOT_7", .size = 7798784, .offset = MTDPART_OFS_NXTBLK },
{ .name = "CS1_EXTRA", .size = MTDPART_SIZ_FULL, .offset = MTDPART_OFS_NXTBLK }
};
static struct flash_platform_data p2kr0_spi0_pdata = {
.name = "SPI0",
.nr_parts = ARRAY_SIZE(p2kr0_spi0_parts),
.parts = p2kr0_spi0_parts,
};
static struct flash_platform_data p2kr0_spi1_pdata = {
.name = "SPI1",
.nr_parts = ARRAY_SIZE(p2kr0_spi1_parts),
.parts = p2kr0_spi1_parts,
};
static struct spi_board_info p2kr0_board_info[] = {
{
.modalias = "n25q256a11",
.bus_num = 1,
.chip_select = 0,
.mode = SPI_MODE_0,
.platform_data = &p2kr0_spi0_pdata
},
{
.modalias = "n25q256a11",
.bus_num = 1,
.chip_select = 1,
.mode = SPI_MODE_0,
.platform_data = &p2kr0_spi1_pdata
},
};
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment