| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- #include <linux/module.h>
- #include <linux/fs.h>
- #include <linux/cdev.h>
- #include <linux/device.h>
- #include <linux/uaccess.h>
- #include <linux/slab.h>
- #include <linux/sched.h>
- #include <linux/io.h>
- #define DEVICE_NAME "com12v"
- #define CLASS_NAME "com12v_class"
- #define MAJOR_NUM 56
- #define MINOR_NUM 20
- #define DEVICE_COUNT 1
- #define NUM_COMPORTS 6
- #define A_LONG_TIME 100 // 10.0 seconds
- #define DEFAULT_DELAY 20 // 2.0 second
- typedef enum
- {
- PPS_OFF = 0,
- PPS_AWAITING_ON,
- PPS_ON,
- NUM_POWER_PORT_STATES
- } ENUM_POWER_PORT_STATES;
- static struct class *com12v_class = NULL;
- static struct device *com12v_device = NULL;
- static struct cdev com12v_cdev;
- static dev_t dev_num;
- static unsigned int muiPowerOnDelayCount = DEFAULT_DELAY;
- static unsigned int mauiPowerPortState[NUM_COMPORTS];
- static struct delayed_work delay_work1;
- static unsigned int com12v_ctl_phy_addr[NUM_COMPORTS] = {0xFD6E0750, 0xFD6E0760, 0xFD6E0770, 0xFD6E0780, 0xFD6D0920, 0xFD6D0930};
- static void __iomem *com12v_ctl_vir_addr[NUM_COMPORTS];
- static void com12v_delay_work_func(struct work_struct *work)
- {
- static unsigned int uiTimeSinceLastPowerOn = A_LONG_TIME;
- int i;
- unsigned int value = 0;
-
- // Keep incrementing the uiTimeSinceLastPowerOn until it is large enough
- // that we can safely assume a long time has passed since the last port
- // transitioned on.
- if (uiTimeSinceLastPowerOn < A_LONG_TIME)
- {
- ++uiTimeSinceLastPowerOn;
- }
- // If a port is waiting to power on and enough time has passed since the
- // last port powered on then go ahead and power on the waiting port. The
- // break statement insure we don't power on more than one port at a time.
- for (i=0; i < NUM_COMPORTS; ++i)
- {
- // printk("%d", mauiPowerPortState[i]);
- if ((mauiPowerPortState[i] == PPS_AWAITING_ON) && (uiTimeSinceLastPowerOn >= muiPowerOnDelayCount))
- {
- mauiPowerPortState[i] = PPS_ON;
- uiTimeSinceLastPowerOn = 0;
- break;
- }
- }
- // printk("\n");
- // Turn on/off hw power supply pins based on current states.
- for (i=0; i < NUM_COMPORTS; ++i)
- {
- if (mauiPowerPortState[i] == PPS_ON)
- {
- value = readl(com12v_ctl_vir_addr[i]);
- value &= 0xfffffffe;
- writel(value, com12v_ctl_vir_addr[i]);
- }
- else if (mauiPowerPortState[i] == PPS_OFF)
- {
- value = readl(com12v_ctl_vir_addr[i]);
- value |= 0x1;
- writel(value, com12v_ctl_vir_addr[i]);
- }
- }
- schedule_delayed_work(&delay_work1, msecs_to_jiffies(100));
- }
- static int com12v_open(struct inode *inode, struct file *file)
- {
- // pr_info("com12v: device opened\n");
- return 0;
- }
- static int com12v_release(struct inode *inode, struct file *file)
- {
- // pr_info("com12v: device closed\n");
- return 0;
- }
- static ssize_t com12v_read(struct file *file, char __user *user_buf,
- size_t len, loff_t *offset)
- {
- size_t read_len;
- return read_len;
- }
- static ssize_t com12v_write(struct file *file, const char __user *user_buf,
- size_t len, loff_t *offset)
- {
- int i = 0;
- int iPortIndex;
- char buff[1024];
- char c;
- size_t write_len;
- if (len > sizeof(buff))
- {
- write_len = sizeof(buff);
- }
- else
- {
- write_len = len;
- }
- if (copy_from_user(buff, user_buf, write_len))
- {
- return -EFAULT;
- }
- for (i = 0; i < write_len; i++)
- {
- c = buff[i];
- if ((c >= 'A') && (c <= 'F'))
- {
- iPortIndex = c - 'A';
- if (muiPowerOnDelayCount == 0)
- {
- mauiPowerPortState[iPortIndex] = PPS_ON;
- }
- else
- {
- if (mauiPowerPortState[iPortIndex] == PPS_OFF)
- {
- mauiPowerPortState[iPortIndex] = PPS_AWAITING_ON;
- }
- }
- }
- else if ((c >= 'a') && (c <= 'f'))
- {
- iPortIndex = c - 'a';
- mauiPowerPortState[iPortIndex] = PPS_OFF;
- }
- else if ((c >= '0') && (c <= '9'))
- {
- muiPowerOnDelayCount = (c - '0') * 10;
- }
- else
- {
- printk("com12v: invalid character %c\n", c);
- }
- }
- return write_len;
- }
- static struct file_operations com12v_fops = {
- .owner = THIS_MODULE,
- .open = com12v_open,
- .release = com12v_release,
- .read = com12v_read,
- .write = com12v_write,
- };
- int com12v_init(void)
- {
- int ret;
- int i = 0;
- for(i = 0; i < NUM_COMPORTS; i++)
- {
- com12v_ctl_vir_addr[i] = ioremap(com12v_ctl_phy_addr[i], 4);
- }
- pr_info("com12v: initializing driver\n");
- memset(mauiPowerPortState, 0, sizeof(mauiPowerPortState));
- INIT_DELAYED_WORK(&delay_work1, com12v_delay_work_func);
- schedule_delayed_work(&delay_work1, msecs_to_jiffies(100));
- dev_num = MKDEV(MAJOR_NUM, MINOR_NUM);
- ret = register_chrdev_region(dev_num, DEVICE_COUNT, DEVICE_NAME);
- if (ret < 0)
- {
- pr_err("com12v: Failed to register device number %d:%d\n",
- MAJOR_NUM, MINOR_NUM);
- return ret;
- }
- cdev_init(&com12v_cdev, &com12v_fops);
- com12v_cdev.owner = THIS_MODULE;
- ret = cdev_add(&com12v_cdev, dev_num, DEVICE_COUNT);
- if (ret < 0)
- {
- pr_err("com12v: Failed to add cdev\n");
- goto err_unregister_region;
- }
- com12v_class = class_create(THIS_MODULE, CLASS_NAME);
- if (IS_ERR(com12v_class))
- {
- pr_err("com12v: Failed to create class\n");
- ret = PTR_ERR(com12v_class);
- goto err_cdev_del;
- }
- com12v_device = device_create(com12v_class, NULL, dev_num,
- NULL, DEVICE_NAME);
- if (IS_ERR(com12v_device))
- {
- pr_err("com12v: Failed to create device\n");
- ret = PTR_ERR(com12v_device);
- goto err_class_destroy;
- }
- pr_info("com12v: driver initialized successfully, device node /dev/%s\n",
- DEVICE_NAME);
- return 0;
- err_class_destroy:
- class_destroy(com12v_class);
- err_cdev_del:
- cdev_del(&com12v_cdev);
- err_unregister_region:
- unregister_chrdev_region(dev_num, DEVICE_COUNT);
- return ret;
- }
- void com12v_exit(void)
- {
- int i = 0;
- cancel_delayed_work_sync(&delay_work1);
- device_destroy(com12v_class, dev_num);
- class_destroy(com12v_class);
- cdev_del(&com12v_cdev);
- unregister_chrdev_region(dev_num, DEVICE_COUNT);
- for(i = 0; i < NUM_COMPORTS; i++)
- {
- iounmap(com12v_ctl_vir_addr[i]);
- }
- pr_info("com12v: driver unloaded\n");
- }
|