drivers: mfd: npm1300: Added event interrupt handling
Added support for npm1300 interrupt events Signed-off-by: Andy Sinclair <andy.sinclair@nordicsemi.no>
This commit is contained in:
parent
5c901052ec
commit
7a71ebe372
3 changed files with 183 additions and 1 deletions
|
@ -10,34 +10,103 @@
|
|||
#include <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/drivers/gpio/gpio_utils.h>
|
||||
#include <zephyr/drivers/mfd/npm1300.h>
|
||||
|
||||
#define TIME_BASE 0x07U
|
||||
#define MAIN_BASE 0x00U
|
||||
#define SHIP_BASE 0x0BU
|
||||
#define GPIO_BASE 0x06U
|
||||
|
||||
#define TIME_OFFSET_LOAD 0x03U
|
||||
#define TIME_OFFSET_TIMER 0x08U
|
||||
|
||||
#define MAIN_OFFSET_RESET 0x01U
|
||||
#define MAIN_OFFSET_RESET 0x01U
|
||||
#define MAIN_OFFSET_SET 0x00U
|
||||
#define MAIN_OFFSET_CLR 0x01U
|
||||
#define MAIN_OFFSET_INTENSET 0x02U
|
||||
#define MAIN_OFFSET_INTENCLR 0x03U
|
||||
|
||||
#define SHIP_OFFSET_HIBERNATE 0x00U
|
||||
|
||||
#define GPIO_OFFSET_MODE 0x00U
|
||||
|
||||
#define TIMER_PRESCALER_MS 16U
|
||||
#define TIMER_MAX 0xFFFFFFU
|
||||
|
||||
#define MAIN_SIZE 0x26U
|
||||
|
||||
#define GPIO_MODE_GPOIRQ 5
|
||||
|
||||
struct mfd_npm1300_config {
|
||||
struct i2c_dt_spec i2c;
|
||||
struct gpio_dt_spec host_int_gpios;
|
||||
uint8_t pmic_int_pin;
|
||||
};
|
||||
|
||||
struct mfd_npm1300_data {
|
||||
struct k_mutex mutex;
|
||||
const struct device *dev;
|
||||
struct gpio_callback gpio_cb;
|
||||
struct k_work work;
|
||||
sys_slist_t callbacks;
|
||||
};
|
||||
|
||||
struct event_reg_t {
|
||||
uint8_t offset;
|
||||
uint8_t mask;
|
||||
};
|
||||
|
||||
static const struct event_reg_t event_reg[NPM1300_EVENT_MAX] = {
|
||||
[NPM1300_EVENT_CHG_COMPLETED] = {0x0AU, 0x10U},
|
||||
[NPM1300_EVENT_CHG_ERROR] = {0x0AU, 0x20U},
|
||||
[NPM1300_EVENT_BATTERY_DETECTED] = {0x0EU, 0x01U},
|
||||
[NPM1300_EVENT_BATTERY_REMOVED] = {0x0EU, 0x02U},
|
||||
[NPM1300_EVENT_SHIPHOLD_PRESS] = {0x12U, 0x01U},
|
||||
[NPM1300_EVENT_WATCHDOG_WARN] = {0x12U, 0x08U},
|
||||
[NPM1300_EVENT_VBUS_DETECTED] = {0x16U, 0x01U},
|
||||
[NPM1300_EVENT_VBUS_REMOVED] = {0x16U, 0x02U}};
|
||||
|
||||
static void gpio_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
|
||||
{
|
||||
struct mfd_npm1300_data *data = CONTAINER_OF(cb, struct mfd_npm1300_data, gpio_cb);
|
||||
|
||||
k_work_submit(&data->work);
|
||||
}
|
||||
|
||||
static void work_callback(struct k_work *work)
|
||||
{
|
||||
struct mfd_npm1300_data *data = CONTAINER_OF(work, struct mfd_npm1300_data, work);
|
||||
uint8_t buf[MAIN_SIZE];
|
||||
int ret;
|
||||
|
||||
/* Read all MAIN registers into temporary buffer */
|
||||
ret = mfd_npm1300_reg_read_burst(data->dev, MAIN_BASE, 0U, buf, sizeof(buf));
|
||||
if (ret < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < NPM1300_EVENT_MAX; i++) {
|
||||
int offset = event_reg[i].offset + MAIN_OFFSET_CLR;
|
||||
|
||||
if ((buf[offset] & event_reg[i].mask) != 0U) {
|
||||
gpio_fire_callbacks(&data->callbacks, data->dev, BIT(i));
|
||||
|
||||
ret = mfd_npm1300_reg_write(data->dev, MAIN_BASE, offset,
|
||||
event_reg[i].mask);
|
||||
if (ret < 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int mfd_npm1300_init(const struct device *dev)
|
||||
{
|
||||
const struct mfd_npm1300_config *config = dev->config;
|
||||
struct mfd_npm1300_data *mfd_data = dev->data;
|
||||
int ret;
|
||||
|
||||
if (!i2c_is_ready_dt(&config->i2c)) {
|
||||
return -ENODEV;
|
||||
|
@ -45,6 +114,43 @@ static int mfd_npm1300_init(const struct device *dev)
|
|||
|
||||
k_mutex_init(&mfd_data->mutex);
|
||||
|
||||
mfd_data->dev = dev;
|
||||
|
||||
if (config->host_int_gpios.port != NULL) {
|
||||
/* Set specified PMIC pin to be interrupt output */
|
||||
ret = mfd_npm1300_reg_write(dev, GPIO_BASE, GPIO_OFFSET_MODE + config->pmic_int_pin,
|
||||
GPIO_MODE_GPOIRQ);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Configure host interrupt GPIO */
|
||||
if (!gpio_is_ready_dt(&config->host_int_gpios)) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = gpio_pin_configure_dt(&config->host_int_gpios, GPIO_INPUT);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpio_init_callback(&mfd_data->gpio_cb, gpio_callback,
|
||||
BIT(config->host_int_gpios.pin));
|
||||
|
||||
ret = gpio_add_callback(config->host_int_gpios.port, &mfd_data->gpio_cb);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
mfd_data->work.handler = work_callback;
|
||||
|
||||
ret = gpio_pin_interrupt_configure_dt(&config->host_int_gpios,
|
||||
GPIO_INT_EDGE_TO_ACTIVE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -137,11 +243,48 @@ int mfd_npm1300_hibernate(const struct device *dev, uint32_t time_ms)
|
|||
return mfd_npm1300_reg_write(dev, SHIP_BASE, SHIP_OFFSET_HIBERNATE, 1U);
|
||||
}
|
||||
|
||||
int mfd_npm1300_add_callback(const struct device *dev, struct gpio_callback *callback)
|
||||
{
|
||||
struct mfd_npm1300_data *data = dev->data;
|
||||
|
||||
/* Enable interrupts for specified events */
|
||||
for (int i = 0; i < NPM1300_EVENT_MAX; i++) {
|
||||
if ((callback->pin_mask & BIT(i)) != 0U) {
|
||||
/* Clear pending interrupt */
|
||||
int ret = mfd_npm1300_reg_write(data->dev, MAIN_BASE,
|
||||
event_reg[i].offset + MAIN_OFFSET_CLR,
|
||||
event_reg[i].mask);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mfd_npm1300_reg_write(data->dev, MAIN_BASE,
|
||||
event_reg[i].offset + MAIN_OFFSET_INTENSET,
|
||||
event_reg[i].mask);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return gpio_manage_callback(&data->callbacks, callback, true);
|
||||
}
|
||||
|
||||
int mfd_npm1300_remove_callback(const struct device *dev, struct gpio_callback *callback)
|
||||
{
|
||||
struct mfd_npm1300_data *data = dev->data;
|
||||
|
||||
return gpio_manage_callback(&data->callbacks, callback, false);
|
||||
}
|
||||
|
||||
#define MFD_NPM1300_DEFINE(inst) \
|
||||
static struct mfd_npm1300_data data_##inst; \
|
||||
\
|
||||
static const struct mfd_npm1300_config config##inst = { \
|
||||
.i2c = I2C_DT_SPEC_INST_GET(inst), \
|
||||
.host_int_gpios = GPIO_DT_SPEC_INST_GET_OR(inst, host_int_gpios, {0}), \
|
||||
.pmic_int_pin = DT_INST_PROP_OR(inst, pmic_int_pin, 0), \
|
||||
}; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(inst, mfd_npm1300_init, NULL, &data_##inst, &config##inst, \
|
||||
|
|
|
@ -10,3 +10,11 @@ include: i2c-device.yaml
|
|||
properties:
|
||||
reg:
|
||||
required: true
|
||||
|
||||
host-int-gpios:
|
||||
type: phandle-array
|
||||
description: Host pin for interrupt input
|
||||
|
||||
pmic-int-pin:
|
||||
type: int
|
||||
description: Pmic pin number for interrupt output
|
||||
|
|
|
@ -20,6 +20,19 @@ extern "C" {
|
|||
#include <stdint.h>
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
|
||||
enum mfd_npm1300_event_t {
|
||||
NPM1300_EVENT_CHG_COMPLETED,
|
||||
NPM1300_EVENT_CHG_ERROR,
|
||||
NPM1300_EVENT_BATTERY_DETECTED,
|
||||
NPM1300_EVENT_BATTERY_REMOVED,
|
||||
NPM1300_EVENT_SHIPHOLD_PRESS,
|
||||
NPM1300_EVENT_WATCHDOG_WARN,
|
||||
NPM1300_EVENT_VBUS_DETECTED,
|
||||
NPM1300_EVENT_VBUS_REMOVED,
|
||||
NPM1300_EVENT_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Read multiple registers from npm1300
|
||||
|
@ -120,6 +133,24 @@ int mfd_npm1300_reset(const struct device *dev);
|
|||
*/
|
||||
int mfd_npm1300_hibernate(const struct device *dev, uint32_t time_ms);
|
||||
|
||||
/**
|
||||
* @brief Add npm1300 event callback
|
||||
*
|
||||
* @param dev npm1300 mfd device
|
||||
* @param callback callback
|
||||
* @return 0 on success, -errno on failure
|
||||
*/
|
||||
int mfd_npm1300_add_callback(const struct device *dev, struct gpio_callback *callback);
|
||||
|
||||
/**
|
||||
* @brief Remove npm1300 event callback
|
||||
*
|
||||
* @param dev npm1300 mfd device
|
||||
* @param callback callback
|
||||
* @return 0 on success, -errno on failure
|
||||
*/
|
||||
int mfd_npm1300_remove_callback(const struct device *dev, struct gpio_callback *callback);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue