1

For leaning purpose i am writing a i2c client kernel module for bmp180 pressure sensor.

My kernel code is ->

#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/uaccess.h>

#define I2C_DEVICE_NAME     "bmp180"

static unsigned int major; /* major number for device */
static unsigned int minor = 0;
static struct class *bmp180_class;

struct my_dev {
    unsigned char *data;
    struct i2c_client *client;
    struct mutex bmp180_mutex;
    int current_pointer;
    struct cdev bmp180_cdev;
 };


 int bmp180_open(struct inode * inode, struct file * filp)
 {
  pr_info("Someone tried to open me\n");
  return 0;
 }

 int bmp180_release(struct inode * inode, struct file * filp)
 {
  pr_info("Someone closed me\n");
  return 0;
 }

 ssize_t bmp180_read (struct file *filp, char __user * buf, size_t count,
                              loff_t * offset)
 {
  pr_info("Nothing to read guy\n");
  return 0;
 }

 ssize_t bmp180_write(struct file * filp, const char __user * buf, size_t count,
                            loff_t * offset)
{
  pr_info("Can't accept any data guy\n");
  return count;
}

struct file_operations bmp180_fops = {
.owner      =    THIS_MODULE,
.open       =       bmp180_open,
.release    =    bmp180_release,
.read       =       bmp180_read,
.write      =      bmp180_write,
};

static const struct of_device_id bmp180_ids[] = {
{ .compatible = "bosch,bmp180", },
{ /* sentinel */ }
};


 static int bmp180_probe (struct i2c_client *client,
            const struct i2c_device_id *id)
{
  struct device *bmp180_device;
  struct my_dev *bmp180_dev = NULL;
  int error;
  dev_t devt = 0;

  /* Get a range of minor numbers (starting with 0) to work with */
  error = alloc_chrdev_region(&devt, 0, 1, I2C_DEVICE_NAME);
  if (error < 0) {
    pr_err("Can't get major number\n");
    return error;
  }
  major = MAJOR(devt);
  pr_info("BMP180 major number = %d\n",major);

  /* Create device class, visible in /sys/class */
  bmp180_class = class_create(THIS_MODULE, "bmp180_char_class");
  if (IS_ERR(bmp180_class)) {
    pr_err("Error creating sdma test module class.\n");
    error=PTR_ERR(bmp180_class);
    goto fail;
  }

  bmp180_dev = (struct my_dev *)kzalloc(sizeof(struct my_dev), GFP_KERNEL);
  if (bmp180_dev == NULL) {
    error = -ENOMEM;
    goto fail;
  }

  bmp180_dev->data = NULL;
  bmp180_dev->client = client;
  bmp180_dev->current_pointer = 0;
  mutex_init(&bmp180_dev->bmp180_mutex);

  /* Initialize the char device and tie a file_operations to it */
  cdev_init(&bmp180_dev->bmp180_cdev, &bmp180_fops);
  bmp180_dev->bmp180_cdev.owner = THIS_MODULE;
  /* Now make the device live for the users to access */
  error=cdev_add(&bmp180_dev->bmp180_cdev, devt, 1);


  if (error){
      pr_err("Error while trying to add %s", I2C_DEVICE_NAME);
      goto fail;
   }


   bmp180_device = device_create(bmp180_class,
                            NULL,   /* no parent device */
                            devt,    /* associated dev_t */
                            NULL,   /* no additional data */
                            I2C_DEVICE_NAME);  /* device name */

   if (IS_ERR(bmp180_device)) {
    pr_err("Error creating sdma test class device.\n");
    class_destroy(bmp180_class);
    cdev_del(&bmp180_dev->bmp180_cdev);
    unregister_chrdev_region(devt, 1);
    return -1;
   }

   i2c_set_clientdata(client, bmp180_dev);
   pr_info("bmp180 char module loaded\n");
   return 0;

  fail:
    if(bmp180_class != NULL){
    device_destroy(bmp180_class, MKDEV(major, minor));
    class_destroy(bmp180_class);
  }
  if (bmp180_dev != NULL)
    kfree(bmp180_dev);
  return error;
  }  

static int bmp180_remove(struct i2c_client *client)
{

  struct my_dev *bmp180_device = i2c_get_clientdata(client);
  device_destroy(bmp180_class, MKDEV(major, 0));

  kfree(bmp180_device->data);
  mutex_destroy(&bmp180_device->bmp180_mutex);
  kfree(bmp180_device);
  class_destroy(bmp180_class);
  unregister_chrdev_region(MKDEV(major, 0), 1);

  pr_info("bmp180 char module Unloaded\n");
  return 0;
}

static const struct i2c_device_id bmp180_id[] = {
 {"bmp180", 0},
 {},
  };

  MODULE_DEVICE_TABLE(i2c, bmp180_id);
  static struct i2c_driver bmp180_i2c_driver = {

    .driver     = {
    .name     = "bmp180",
    .owner    = THIS_MODULE,
    .of_match_table = of_match_ptr(bmp180_ids),
  },
   .probe      = bmp180_probe,
   .remove     = bmp180_remove,
  .id_table   = bmp180_id,
   };
   module_i2c_driver(bmp180_i2c_driver);
   MODULE_AUTHOR("Prateek Singh <prateeksingh22@hotmail.com>");
   MODULE_LICENSE("GPL");

Added device on device tree at I2C0 bus in bcm2835-rpi-b-plus.dts by following method ->

  // SPDX-License-Identifier: GPL-2.0
   /dts-v1/;
   #include "bcm2835.dtsi"
   #include "bcm2835-rpi.dtsi"
   #include "bcm283x-rpi-smsc9514.dtsi"
   #include "bcm283x-rpi-usb-host.dtsi"
   #include "bcm283x-rpi-csi1-2lane.dtsi"
 / {
   compatible = "raspberrypi,model-b-plus", "brcm,bcm2835";
   model = "Raspberry Pi Model B+";

   leds {
    act {
        gpios = <&gpio 47 GPIO_ACTIVE_HIGH>;
    };

    pwr {
        label = "PWR";
        gpios = <&gpio 35 GPIO_ACTIVE_HIGH>;
        default-state = "keep";
        linux,default-trigger = "default-on";
      };
   };
  };

&gpio {
/*
 * Taken from Raspberry-Pi-B-Plus-V1.2-Schematics.pdf
 * RPI-BPLUS sheet 1
 *
 * Legend:
 * "NC" = not connected (no rail from the SoC)
 * "FOO" = GPIO line named "FOO" on the schematic
 * "FOO_N" = GPIO line named "FOO" on schematic, active low
 */
gpio-line-names = "SDA0",
          "SCL0",
          "SDA1",
          "SCL1",
          "GPIO_GCLK",
          "GPIO5",
          "GPIO6",
          "SPI_CE1_N",
          "SPI_CE0_N",
          "SPI_MISO",
          "SPI_MOSI",
          "SPI_SCLK",
          "GPIO12",
          "GPIO13",
          /* Serial port */
          "TXD0",
          "RXD0",
          "GPIO16",
          "GPIO17",
          "GPIO18",
          "GPIO19",
          "GPIO20",
          "GPIO21",
          "GPIO22",
          "GPIO23",
          "GPIO24",
          "GPIO25",
          "GPIO26",
          "GPIO27",
          "SDA0",
          "SCL0",
          "NC", /* GPIO30 */
          "LAN_RUN", /* GPIO31 */
          "CAM_GPIO1", /* GPIO32 */
          "NC", /* GPIO33 */
          "NC", /* GPIO34 */
          "PWR_LOW_N", /* GPIO35 */
          "NC", /* GPIO36 */
          "NC", /* GPIO37 */
          "USB_LIMIT", /* GPIO38 */
          "NC", /* GPIO39 */
          "PWM0_OUT", /* GPIO40 */
          "CAM_GPIO0", /* GPIO41 */
          "NC", /* GPIO42 */
          "NC", /* GPIO43 */
          "ETHCLK", /* GPIO44 */
          "PWM1_OUT", /* GPIO45 */
          "HDMI_HPD_N",
          "STATUS_LED",
          /* Used by SD Card */
          "SD_CLK_R",
          "SD_CMD_R",
          "SD_DATA0_R",
          "SD_DATA1_R",
          "SD_DATA2_R",
          "SD_DATA3_R";

pinctrl-0 = <&gpioout &alt0 &i2s_alt0>;

   /* I2S interface */
   i2s_alt0: i2s_alt0 {
       brcm,pins = <18 19 20 21>;
      brcm,function = <BCM2835_FSEL_ALT0>;
     };
 };

   &hdmi {
     hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
     power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
     status = "okay";
     };

   &pwm {
     pinctrl-names = "default";
     pinctrl-0 = <&pwm0_gpio40 &pwm1_gpio45>;
     status = "okay";
     };

   &sdhost {
     pinctrl-names = "default";
    pinctrl-0 = <&sdhost_gpio48>;
    bus-width = <4>;
    status = "okay";
    };

  &uart0 {
   pinctrl-names = "default";
   pinctrl-0 = <&uart0_gpio14>;
   status = "okay";
     };
  &i2c0 {

   pinctrl-names = "default";
   pinctrl-0    =   <&i2c0_gpio0>;
   status = "okay";
   clock-frequency = <4000000>;

   presure-sensor@77 {
   compatible   = "bosch,bmp180";
   reg = <0x77>;
    };
  };

All this i am implementing in rpi 3 b plus and able to build kernel code without any error. But after attaching device bmp180 at gpio 2 & 3 , I loaded module by insmod but its not going inside probe method as i am not getting any print present in probe method.

Could anybody tell me what i am missing by reviewing the above code and device tree.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.