Pārlūkot izejas kodu

添加COM12V驱动

liu qidong 1 nedēļu atpakaļ
vecāks
revīzija
97d50214e7
4 mainītis faili ar 272 papildinājumiem un 1 dzēšanām
  1. 1 1
      Makefile
  2. 255 0
      com12v.c
  3. 5 0
      com12v.h
  4. 11 0
      main.c

+ 1 - 1
Makefile

@@ -3,7 +3,7 @@
 MODULE_NAME := opal
 obj-m := opal.o
 
-opal-objs := main.o led.o light_ring.o ssegment.o ec_version.o buzzer.o fan.o writeprotect.o myname.o cash_drawers.o batteryled.o watchdog.o power.o switches.o backlight.o gsensor.o lcd_2x20.o smart_battery.o voltage_sysfs.o led_heartbeat.o sysfs_power.o vbat.o temperature_sysfs.o
+opal-objs := main.o led.o light_ring.o ssegment.o ec_version.o buzzer.o fan.o writeprotect.o myname.o cash_drawers.o batteryled.o watchdog.o power.o switches.o backlight.o gsensor.o lcd_2x20.o smart_battery.o voltage_sysfs.o led_heartbeat.o sysfs_power.o vbat.o temperature_sysfs.o com12v.o
 
 PROJECT_NAME ?= 1
 POS ?= 1

+ 255 - 0
com12v.c

@@ -0,0 +1,255 @@
+#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");
+}
+

+ 5 - 0
com12v.h

@@ -0,0 +1,5 @@
+#ifndef __COM12V_H__
+#define __COM12V_H__
+int com12v_init(void);
+void com12v_exit(void);
+#endif

+ 11 - 0
main.c

@@ -38,6 +38,7 @@
 #include "sysfs_power.h"
 #include "vbat.h"
 #include "temperature_sysfs.h"
+#include "com12v.h"
 
 struct kobject *vfiec_kobj = NULL;
 struct kobject *hwmon_kobj = NULL;
@@ -200,8 +201,17 @@ static int __init all_driver_init(void)
         goto out_vbat;
     }
 
+    ret = com12v_init();
+    if(ret != 0)
+    {
+        printk(KERN_ERR "com12v_init failed\n");
+        goto out_temperature_sysfs;
+    }
+
     printk(KERN_INFO "all_driver_init\n");
     return ret;
+out_com12v:
+    com12v_exit();
 out_temperature_sysfs:
     temperature_sysfs_exit();
 out_vbat:
@@ -276,6 +286,7 @@ static void __exit all_driver_exit(void)
     sysfs_power_exit();
     vbat_exit();
     temperature_sysfs_exit();
+    com12v_exit();
     kobject_put(hwmon_kobj);
     kobject_put(vfiec_kobj);
 }