zephyr/drivers/i2c/i2c_mcux_lpi2c.c
Maureen Helm 7242660399 drivers: i2c: Refactor mcux lpi2c driver to use generated dts macros
Refactors the mcux lpi2c driver to use generated device tree macros
directly. Removes now unused dts fixup macros from i.mx rt and kinetis
socs.

Signed-off-by: Maureen Helm <maureen.helm@nxp.com>
2020-01-14 11:10:27 -05:00

383 lines
10 KiB
C

/*
* Copyright (c) 2016 Freescale Semiconductor, Inc.
* Copyright (c) 2019, NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <drivers/i2c.h>
#include <drivers/clock_control.h>
#include <fsl_lpi2c.h>
#include <logging/log.h>
LOG_MODULE_REGISTER(mcux_lpi2c);
#include "i2c-priv.h"
struct mcux_lpi2c_config {
LPI2C_Type *base;
char *clock_name;
clock_control_subsys_t clock_subsys;
void (*irq_config_func)(struct device *dev);
u32_t bitrate;
u32_t bus_idle_timeout_ns;
};
struct mcux_lpi2c_data {
lpi2c_master_handle_t handle;
struct k_sem device_sync_sem;
status_t callback_status;
};
static int mcux_lpi2c_configure(struct device *dev, u32_t dev_config_raw)
{
const struct mcux_lpi2c_config *config = dev->config->config_info;
LPI2C_Type *base = config->base;
struct device *clock_dev;
u32_t clock_freq;
u32_t baudrate;
if (!(I2C_MODE_MASTER & dev_config_raw)) {
return -EINVAL;
}
if (I2C_ADDR_10_BITS & dev_config_raw) {
return -EINVAL;
}
switch (I2C_SPEED_GET(dev_config_raw)) {
case I2C_SPEED_STANDARD:
baudrate = KHZ(100);
break;
case I2C_SPEED_FAST:
baudrate = MHZ(1);
break;
default:
return -EINVAL;
}
clock_dev = device_get_binding(config->clock_name);
if (clock_dev == NULL) {
return -EINVAL;
}
if (clock_control_get_rate(clock_dev, config->clock_subsys,
&clock_freq)) {
return -EINVAL;
}
LPI2C_MasterSetBaudRate(base, clock_freq, baudrate);
return 0;
}
static void mcux_lpi2c_master_transfer_callback(LPI2C_Type *base,
lpi2c_master_handle_t *handle, status_t status, void *userData)
{
struct device *dev = userData;
struct mcux_lpi2c_data *data = dev->driver_data;
ARG_UNUSED(handle);
ARG_UNUSED(base);
data->callback_status = status;
k_sem_give(&data->device_sync_sem);
}
static u32_t mcux_lpi2c_convert_flags(int msg_flags)
{
u32_t flags = 0U;
if (!(msg_flags & I2C_MSG_STOP)) {
flags |= kLPI2C_TransferNoStopFlag;
}
if (msg_flags & I2C_MSG_RESTART) {
flags |= kLPI2C_TransferRepeatedStartFlag;
}
return flags;
}
static int mcux_lpi2c_transfer(struct device *dev, struct i2c_msg *msgs,
u8_t num_msgs, u16_t addr)
{
const struct mcux_lpi2c_config *config = dev->config->config_info;
struct mcux_lpi2c_data *data = dev->driver_data;
LPI2C_Type *base = config->base;
lpi2c_master_transfer_t transfer;
status_t status;
/* Iterate over all the messages */
for (int i = 0; i < num_msgs; i++) {
if (I2C_MSG_ADDR_10_BITS & msgs->flags) {
return -ENOTSUP;
}
/* Initialize the transfer descriptor */
transfer.flags = mcux_lpi2c_convert_flags(msgs->flags);
/* Prevent the controller to send a start condition between
* messages, except if explicitly requested.
*/
if (i != 0 && !(msgs->flags & I2C_MSG_RESTART)) {
transfer.flags |= kLPI2C_TransferNoStartFlag;
}
transfer.slaveAddress = addr;
transfer.direction = (msgs->flags & I2C_MSG_READ)
? kLPI2C_Read : kLPI2C_Write;
transfer.subaddress = 0;
transfer.subaddressSize = 0;
transfer.data = msgs->buf;
transfer.dataSize = msgs->len;
/* Start the transfer */
status = LPI2C_MasterTransferNonBlocking(base,
&data->handle, &transfer);
/* Return an error if the transfer didn't start successfully
* e.g., if the bus was busy
*/
if (status != kStatus_Success) {
return -EIO;
}
/* Wait for the transfer to complete */
k_sem_take(&data->device_sync_sem, K_FOREVER);
/* Return an error if the transfer didn't complete
* successfully. e.g., nak, timeout, lost arbitration
*/
if (data->callback_status != kStatus_Success) {
return -EIO;
}
/* Move to the next message */
msgs++;
}
return 0;
}
static void mcux_lpi2c_isr(void *arg)
{
struct device *dev = (struct device *)arg;
const struct mcux_lpi2c_config *config = dev->config->config_info;
struct mcux_lpi2c_data *data = dev->driver_data;
LPI2C_Type *base = config->base;
LPI2C_MasterTransferHandleIRQ(base, &data->handle);
}
static int mcux_lpi2c_init(struct device *dev)
{
const struct mcux_lpi2c_config *config = dev->config->config_info;
struct mcux_lpi2c_data *data = dev->driver_data;
LPI2C_Type *base = config->base;
struct device *clock_dev;
u32_t clock_freq, bitrate_cfg;
lpi2c_master_config_t master_config;
int error;
k_sem_init(&data->device_sync_sem, 0, UINT_MAX);
clock_dev = device_get_binding(config->clock_name);
if (clock_dev == NULL) {
return -EINVAL;
}
if (clock_control_get_rate(clock_dev, config->clock_subsys,
&clock_freq)) {
return -EINVAL;
}
LPI2C_MasterGetDefaultConfig(&master_config);
master_config.busIdleTimeout_ns = config->bus_idle_timeout_ns;
LPI2C_MasterInit(base, &master_config, clock_freq);
LPI2C_MasterTransferCreateHandle(base, &data->handle,
mcux_lpi2c_master_transfer_callback, dev);
bitrate_cfg = i2c_map_dt_bitrate(config->bitrate);
error = mcux_lpi2c_configure(dev, I2C_MODE_MASTER | bitrate_cfg);
if (error) {
return error;
}
config->irq_config_func(dev);
return 0;
}
static const struct i2c_driver_api mcux_lpi2c_driver_api = {
.configure = mcux_lpi2c_configure,
.transfer = mcux_lpi2c_transfer,
};
#ifdef CONFIG_I2C_0
static void mcux_lpi2c_config_func_0(struct device *dev);
static const struct mcux_lpi2c_config mcux_lpi2c_config_0 = {
.base = (LPI2C_Type *)DT_NXP_IMX_LPI2C_I2C_0_BASE_ADDRESS,
.clock_name = DT_NXP_IMX_LPI2C_I2C_0_CLOCK_CONTROLLER,
.clock_subsys =
(clock_control_subsys_t) DT_NXP_IMX_LPI2C_I2C_0_CLOCK_NAME,
.irq_config_func = mcux_lpi2c_config_func_0,
.bitrate = DT_NXP_IMX_LPI2C_I2C_0_CLOCK_FREQUENCY,
#if DT_NXP_IMX_LPI2C_I2C_0_BUS_IDLE_TIMEOUT
.bus_idle_timeout_ns = DT_NXP_IMX_LPI2C_I2C_0_BUS_IDLE_TIMEOUT,
#endif
};
static struct mcux_lpi2c_data mcux_lpi2c_data_0;
DEVICE_AND_API_INIT(mcux_lpi2c_0, DT_NXP_IMX_LPI2C_I2C_0_LABEL,
&mcux_lpi2c_init,
&mcux_lpi2c_data_0, &mcux_lpi2c_config_0,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&mcux_lpi2c_driver_api);
static void mcux_lpi2c_config_func_0(struct device *dev)
{
IRQ_CONNECT(DT_NXP_IMX_LPI2C_I2C_0_IRQ_0,
DT_NXP_IMX_LPI2C_I2C_0_IRQ_0_PRIORITY,
mcux_lpi2c_isr, DEVICE_GET(mcux_lpi2c_0), 0);
irq_enable(DT_NXP_IMX_LPI2C_I2C_0_IRQ_0);
}
#endif /* CONFIG_I2C_0 */
#ifdef CONFIG_I2C_1
static void mcux_lpi2c_config_func_1(struct device *dev);
static const struct mcux_lpi2c_config mcux_lpi2c_config_1 = {
.base = (LPI2C_Type *)DT_NXP_IMX_LPI2C_I2C_1_BASE_ADDRESS,
.clock_name = DT_NXP_IMX_LPI2C_I2C_1_CLOCK_CONTROLLER,
.clock_subsys =
(clock_control_subsys_t) DT_NXP_IMX_LPI2C_I2C_1_CLOCK_NAME,
.irq_config_func = mcux_lpi2c_config_func_1,
.bitrate = DT_NXP_IMX_LPI2C_I2C_1_CLOCK_FREQUENCY,
#if DT_NXP_IMX_LPI2C_I2C_1_BUS_IDLE_TIMEOUT
.bus_idle_timeout_ns = DT_NXP_IMX_LPI2C_I2C_1_BUS_IDLE_TIMEOUT,
#endif
};
static struct mcux_lpi2c_data mcux_lpi2c_data_1;
DEVICE_AND_API_INIT(mcux_lpi2c_1, DT_NXP_IMX_LPI2C_I2C_1_LABEL,
&mcux_lpi2c_init,
&mcux_lpi2c_data_1, &mcux_lpi2c_config_1,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&mcux_lpi2c_driver_api);
static void mcux_lpi2c_config_func_1(struct device *dev)
{
IRQ_CONNECT(DT_NXP_IMX_LPI2C_I2C_1_IRQ_0,
DT_NXP_IMX_LPI2C_I2C_1_IRQ_0_PRIORITY,
mcux_lpi2c_isr, DEVICE_GET(mcux_lpi2c_1), 0);
irq_enable(DT_NXP_IMX_LPI2C_I2C_1_IRQ_0);
}
#endif /* CONFIG_I2C_1 */
#ifdef CONFIG_I2C_2
static void mcux_lpi2c_config_func_2(struct device *dev);
static const struct mcux_lpi2c_config mcux_lpi2c_config_2 = {
.base = (LPI2C_Type *)DT_NXP_IMX_LPI2C_I2C_2_BASE_ADDRESS,
.clock_name = DT_NXP_IMX_LPI2C_I2C_2_CLOCK_CONTROLLER,
.clock_subsys =
(clock_control_subsys_t) DT_NXP_IMX_LPI2C_I2C_2_CLOCK_NAME,
.irq_config_func = mcux_lpi2c_config_func_2,
.bitrate = DT_NXP_IMX_LPI2C_I2C_2_CLOCK_FREQUENCY,
#if DT_NXP_IMX_LPI2C_I2C_2_BUS_IDLE_TIMEOUT
.bus_idle_timeout_ns = DT_NXP_IMX_LPI2C_I2C_2_BUS_IDLE_TIMEOUT,
#endif
};
static struct mcux_lpi2c_data mcux_lpi2c_data_2;
DEVICE_AND_API_INIT(mcux_lpi2c_2, DT_NXP_IMX_LPI2C_I2C_2_LABEL,
&mcux_lpi2c_init,
&mcux_lpi2c_data_2, &mcux_lpi2c_config_2,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&mcux_lpi2c_driver_api);
static void mcux_lpi2c_config_func_2(struct device *dev)
{
IRQ_CONNECT(DT_NXP_IMX_LPI2C_I2C_2_IRQ_0,
DT_NXP_IMX_LPI2C_I2C_2_IRQ_0_PRIORITY,
mcux_lpi2c_isr, DEVICE_GET(mcux_lpi2c_2), 0);
irq_enable(DT_NXP_IMX_LPI2C_I2C_2_IRQ_0);
}
#endif /* CONFIG_I2C_2 */
#ifdef CONFIG_I2C_3
static void mcux_lpi2c_config_func_3(struct device *dev);
static const struct mcux_lpi2c_config mcux_lpi2c_config_3 = {
.base = (LPI2C_Type *)DT_NXP_IMX_LPI2C_I2C_3_BASE_ADDRESS,
.clock_name = DT_NXP_IMX_LPI2C_I2C_3_CLOCK_CONTROLLER,
.clock_subsys =
(clock_control_subsys_t) DT_NXP_IMX_LPI2C_I2C_3_CLOCK_NAME,
.irq_config_func = mcux_lpi2c_config_func_3,
.bitrate = DT_NXP_IMX_LPI2C_I2C_3_CLOCK_FREQUENCY,
#if DT_NXP_IMX_LPI2C_I2C_3_BUS_IDLE_TIMEOUT
.bus_idle_timeout_ns = DT_NXP_IMX_LPI2C_I2C_3_BUS_IDLE_TIMEOUT,
#endif
};
static struct mcux_lpi2c_data mcux_lpi2c_data_3;
DEVICE_AND_API_INIT(mcux_lpi2c_3, DT_NXP_IMX_LPI2C_I2C_3_LABEL,
&mcux_lpi2c_init,
&mcux_lpi2c_data_3, &mcux_lpi2c_config_3,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&mcux_lpi2c_driver_api);
static void mcux_lpi2c_config_func_3(struct device *dev)
{
IRQ_CONNECT(DT_NXP_IMX_LPI2C_I2C_3_IRQ_0,
DT_NXP_IMX_LPI2C_I2C_3_IRQ_0_PRIORITY,
mcux_lpi2c_isr, DEVICE_GET(mcux_lpi2c_3), 0);
irq_enable(DT_NXP_IMX_LPI2C_I2C_3_IRQ_0);
}
#endif /* CONFIG_I2C_3 */
#ifdef CONFIG_I2C_4
static void mcux_lpi2c_config_func_4(struct device *dev);
static const struct mcux_lpi2c_config mcux_lpi2c_config_4 = {
.base = (LPI2C_Type *)DT_NXP_IMX_LPI2C_I2C_4_BASE_ADDRESS,
.clock_name = DT_NXP_IMX_LPI2C_I2C_4_CLOCK_CONTROLLER,
.clock_subsys =
(clock_control_subsys_t) DT_NXP_IMX_LPI2C_I2C_4_CLOCK_NAME,
.irq_config_func = mcux_lpi2c_config_func_4,
.bitrate = DT_NXP_IMX_LPI2C_I2C_4_CLOCK_FREQUENCY,
#if DT_NXP_IMX_LPI2C_I2C_4_BUS_IDLE_TIMEOUT
.bus_idle_timeout_ns = DT_NXP_IMX_LPI2C_I2C_4_BUS_IDLE_TIMEOUT,
#endif
};
static struct mcux_lpi2c_data mcux_lpi2c_data_4;
DEVICE_AND_API_INIT(mcux_lpi2c_4, DT_NXP_IMX_LPI2C_I2C_4_LABEL,
&mcux_lpi2c_init,
&mcux_lpi2c_data_4, &mcux_lpi2c_config_4,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&mcux_lpi2c_driver_api);
static void mcux_lpi2c_config_func_4(struct device *dev)
{
IRQ_CONNECT(DT_NXP_IMX_LPI2C_I2C_4_IRQ_0,
DT_NXP_IMX_LPI2C_I2C_4_IRQ_0_PRIORITY,
mcux_lpi2c_isr, DEVICE_GET(mcux_lpi2c_4), 0);
irq_enable(DT_NXP_IMX_LPI2C_I2C_4_IRQ_0);
}
#endif /* CONFIG_I2C_4 */