Creation of custom driver for an i2c device

Hi All,

(Edit: I mistakenly referred to drivers included in the project's structure as "in-tree")

I need to interface with a Monolitic's MP2731 battery charger, it has an i2c interface, and want to create a custom in-tree out of tree driver for it.

My question is, Is there a working example demonstrating how to structure, configure and create a custom driver for a device in an i2c bus?

I prefer to create an in-tree out of tree driver, inside the project's source tree, for not to interfere with Zephyr's own source and configuration files. I'll mention here that I've already faced the issue covered [here].

What I've done so far is:

In my project's root, under "drivers/mp2731", I created following files:

- CMakeLists.txt, has just two lines: zephyr_library() and zephyr_library_sources(mp2731.c).

- mp2731.c, the source code, just an almost empty skeleton:

#include <errno.h>

#include "zephyr/device.h"
#include "zephyr/drivers/charger.h"
#include "zephyr/drivers/i2c.h"
#include "zephyr/kernel.h"
#include "zephyr/sys/util.h"
#include "MP2731.h"

// #if MP2731_BATTERY_CHARGER
#define DT_DRV_COMPAT monolitic_mp2731

struct mp2731_config {
   struct i2c_dt_spec i2c;
};

static int mp2731_init(const struct device *dev) {
   const struct mp2731_config *const config = dev->config;
   // struct mp2731_data *data = dev->data;
   uint8_t val;
   int ret;

   ret = i2c_reg_read_byte_dt(&config->i2c, 0, &val);
   if (ret) {
      return ret;
   }

   return ret;
}

static int mp2731_get_prop(const struct device *dev, charger_prop_t prop, union charger_propval *val) {
      switch (prop) {
         default:
            return -ENOTSUP;
      }
}

static int mp2731_set_prop(const struct device *dev, charger_prop_t prop, const union charger_propval *val) {
   switch (prop) {
      default:
         return -ENOTSUP;
   }
}

static const struct charger_driver_api mp2731_driver_api = {
   .get_property = &mp2731_get_prop,
   .set_property = &mp2731_set_prop,
};

#define MP2731_INIT(inst) \
\
   static const struct mp2731_config mp2731_config_##inst = { \
      .i2c = I2C_DT_SPEC_INST_GET(inst), \
   }; \
\
   DEVICE_DT_INST_DEFINE(inst, &mp2731_init, NULL, NULL, \
      &mp2731_config_##inst, POST_KERNEL, CONFIG_CHARGER_INIT_PRIORITY, \
      &mp2731_driver_api);

DT_INST_FOREACH_STATUS_OKAY(MP2731_INIT)

// #endif // MP2731_BATTERY_CHARGER

- Kconfig.mp2731, with content:

config MP2731_BATTERY_CHARGER
    bool "MP2731 Battery charger"
        default y
    help
        Enable driver for the MP2731 Battery charger controllers.

Under the drivers directory:

- a CMakeLists.txt file with a single line: add_subdirectory(mp2731)

I added the line add_subdirectory(drivers) to the project's CMakeLists.txt file.

Under the directory "dts/bindings/drivers" I created a bindings file named monolitic,mp2731.yaml, with following content:

description: Driver para cargador de baterías MP2731
compatible: "monolitic,mp2731"
include: [i2c-device.yaml, battery.yaml]

In the project's .overlay file I inserted following section:

&i2c1 {
     status = "okay";
     batchg0: batchg_0@4B {
          compatible = "monolitic,mp2731";
          reg = < 0x4B >;
          label = "batchg";
     };
};

One of the error messages I receive is "node '/soc/i2c@40004000/batchg_0@4B' compatible 'monolitic,mp2731' has unknown vendor prefix 'monolitic'".

The linker also outputs "undefined reference to `__device_dts_ord_92'". I see a file named "libC____...etc...__drivers__mp2731.a" is generated, it contains the symbol, but it seems it is not automatically linked to the application.

BR

Related