說明:

  平臺設備:正點原子IMX6ULL,板子自帶ap3216c

 

第一部分:

  修改設備樹,添加ap3216c設備:

&i2c1 {
  clock-frequency = <100000>;
  pinctrl-names = "default";
  pinctrl-0 = <&pinctrl_i2c1>;
  status = "okay";

 

  ap3216c@1e {
  compatible = "fsl,ap3216c";
  reg = <0x1e>;
  };
};

 

 

第二部分:

  i2c_ap3216c.c 驅(qū)動文件:

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/i2c.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#include "i2c_ap3216c.h"

struct ap3216c_dev {
  dev_t devid;
  int major;
  int minor;
  struct cdev cdev;
  struct class *class;
  struct device *device;
  void *private_data;
  unsigned short ir, als, ps;
};

struct ap3216c_dev ap3216c;

static int i2c_write_reg(unsigned char addr, unsigned char para)
{
  unsigned char data[2];
  struct i2c_msg msg;
  struct i2c_client *client = (struct i2c_client *)ap3216c.private_data;

  data[0] = addr;
  data[1] = para;

  msg.addr = client->addr;
  msg.flags = 0;
  msg.buf = data;
  msg.len = 2;

  return i2c_transfer(client->adapter, &msg, 1);
}

static int i2c_read_reg(unsigned char addr, unsigned char *value)
{
  struct i2c_msg msg[2];
  struct i2c_client *client = (struct i2c_client *)ap3216c.private_data;

  msg[0].addr = client->addr;
  msg[0].flags = 0;         //寫標記
  msg[0].buf = &addr;       //讀取的地址
  msg[0].len = 1;              //要發(fā)送的數(shù)據(jù)長度

  msg[1].addr = client->addr;
  msg[1].flags = I2C_M_RD;     //標記為讀數(shù)據(jù)
  msg[1].buf = value;          //讀取的地址
  msg[1].len = 1;              //要讀取的數(shù)據(jù)長度

  return i2c_transfer(client->adapter, msg, 2);
}

void ap3216c_init(void)
{
  i2c_write_reg(ADDR_SYSTEM_CFG, CMD_RST);
  mdelay(50);
  i2c_write_reg(ADDR_SYSTEM_CFG, CMD_CFG_ALS_PS_IR);
}

static int ap3216c_open(struct inode *inode, struct file *filp)
{
  printk("ap3216c_open \r\n");
  
  ap3216c_init();

  return 0;
}

static int ap3216c_write(struct file *file, const char __user *buf,size_t count, loff_t *pos)
{
  printk("ap3216c_write \r\n");

  return 0;
}

static ssize_t ap3216c_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
  int ret, i;

  unsigned short data[3];

  unsigned char pbuf[6];

  printk("ap3216c_read \r\n");

  for(i=0; i<6; i++)
  {
    i2c_read_reg(ADDR_IR_DATA_LOW + i, &pbuf[i]);
  }

  if(pbuf[0] & 0x80)
  {
    data[0] = ap3216c.ir = 0;
  }
  else
  {
    data[0] = ap3216c.ir = (unsigned short)(pbuf[1] << 2) | (pbuf[0] & 0x03);
  }

  data[1] = ap3216c.als = (unsigned short)(pbuf[3] << 8) | pbuf[2];
  
  if(pbuf[4] & 0x40)
  {
    data[2] = ap3216c.ps = 0;
  }
  else
  {
    data[2] = ap3216c.ps = (unsigned short)((pbuf[5] & 0x3f) << 4) | (pbuf[4] & 0x0f);
  }

  ret = copy_to_user(buf, data, sizeof(data));

  if(ret)
  {
    printk("copy to user failed \r\n");
  }

  return 0;
}

static struct file_operations ap3216c_fops = {
  .owner = THIS_MODULE,
  .open = ap3216c_open,
  .read = ap3216c_read,
  .write = ap3216c_write,
};

static int ap3216c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
  printk("ap3216c_probe \r\n");

  if(ap3216c.major)                                                                   //申請設備號
  {
    ap3216c.devid = MKDEV(ap3216c.major, 0);
    register_chrdev_region(ap3216c.devid, DEV_CNT, DEV_NAME);
  }
  else
  {
    alloc_chrdev_region(&ap3216c.devid, 0, DEV_CNT, DEV_NAME);
    ap3216c.major = MAJOR(ap3216c.devid);
    ap3216c.minor = MINOR(ap3216c.devid);
  }

  cdev_init(&ap3216c.cdev, &ap3216c_fops);                                            //初始化字符設備, 并向內(nèi)核進行添加
  cdev_add(&ap3216c.cdev, ap3216c.devid, DEV_CNT);

  ap3216c.class = class_create(THIS_MODULE, DEV_NAME);                                //創(chuàng)建設備類

  if (IS_ERR(ap3216c.class))
  {
    printk("class create fail \r\n");
    return PTR_ERR(ap3216c.class);
  }

  ap3216c.device = device_create(ap3216c.class, NULL, ap3216c.devid, NULL, DEV_NAME); //創(chuàng)建設備
  if (IS_ERR(ap3216c.device))
  {
    printk("device create fail \r\n");
    return PTR_ERR(ap3216c.device);
  }

  ap3216c.private_data = client;

  return 0;
}

static int ap3216c_remove(struct i2c_client *client)
{
  printk("ap3216c_remove \r\n");

  cdev_del(&ap3216c.cdev);                                                            //注銷設字符設備
  unregister_chrdev_region(ap3216c.devid, DEV_CNT);                                   //注銷設備號

  device_destroy(ap3216c.class, ap3216c.devid);                                       //注銷設備類
  class_destroy(ap3216c.class);                                                       //注銷設備

  return 0;
}


static const struct i2c_device_id ap3216c_id[] = {
  {"fsl,ap3216c", 0},
  { },

};

static struct of_device_id ap3216c_of_match[] = {
  {.compatible = "fsl,ap3216c"},
  { },
};

static struct i2c_driver ap3216c_dirver = {
  .probe = ap3216c_probe,
  .remove = ap3216c_remove,
  .id_table = ap3216c_id,

  .driver = {
  .owner = THIS_MODULE,
  .name = "ap3216c",
  .of_match_table = ap3216c_of_match,
  },
};

static int __init ap3216c_module_init(void)
{
  int ret = 0;

  printk("ap3216c_init \r\n");

  ret = i2c_add_driver(&ap3216c_dirver);

  return ret;
}

static void __exit ap3216c_module_exit(void)
{
  printk("ap3216c_exit \r\n");

  i2c_del_driver(&ap3216c_dirver);
}

module_init(ap3216c_module_init);
module_exit(ap3216c_module_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("lianmeng");

 

oled.h 頭文件:

#ifndef __I2C_AP3216C_H
#define __I2C_AP3216C_H

#define DEV_CNT 1
#define DEV_NAME "ap3216c"

#define CMD_RST 0x04
#define CMD_CFG_ALS_PS_IR 0x03

#define ADDR_SYSTEM_CFG 0x00
#define ADDR_IR_DATA_LOW 0x0A
#define ADDR_IR_DATA_HIGH 0x0B
#define ADDR_ALS_DATA_LOW 0x0C
#define ADDR_ALS_DATA_HIGH 0x0D
#define ADDR_PS_DATA_LOW 0x0E
#define ADDR_PS_DATA_HIGH 0x0F

#endif

 

 

第三部分:

  Makefile 文件:

KERNELDIR := /home/lmeng/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek

CURRENT_PATH := $(shell pwd)

obj-m := i2c_ap3216c.o

build : kernel_modules

kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules

clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

 

 

第四部分:

  ap3216cApp.c 應用文件

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/ioctl.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include <poll.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
  int fd, ret;
  char *filename;
  unsigned short buf[3];
  unsigned short ir, als, ps;

  filename = argv[1];

  fd = open(filename, O_RDWR);
  if(fd < 0)
  {
    printf("can't open file %s \r\n", filename);
    return -1;
  }

  while(1)
  {
    ret = read(fd, buf, sizeof(buf));
    if(ret)
    {
      printf("read data failed \r\n");
      return -1;
    }
    else
    {
      ir = buf[0];
      als = buf[1];
      ps = buf[2];

      printf("ir = %d, als = %d, ps = %d \r\n", ir, als, ps);
    }

    usleep(200000);
  }

  close(fd);

  return 0;
}