blob: c56555cb9cd1c2ccb1477a3603ee1ecb03e3b706 [file] [log] [blame]
/**
* Copyright (c) 2015 Runtime Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <assert.h>
#include <errno.h>
#include "syscfg/syscfg.h"
#include "compiler.h"
#include "port.h"
#include "i2c_master.h"
#include "hal/hal_i2c.h"
#include "mcu/hal_i2c.h"
#include "mcu/samd21.h"
#include "samd21_priv.h"
/*
* XXX Timeout value parameter in functions is not used, because Atmel's
* SDK for i2c internally times out much faster than one OS tick takes.
*/
struct samd21_i2c_state {
struct i2c_master_module module;
const struct samd21_i2c_config *pconfig;
Sercom *hw;
};
#define HAL_SAMD21_I2C_MAX (6)
#if MYNEWT_VAL(I2C_0)
static struct samd21_i2c_state samd21_i2c0;
#endif
#if MYNEWT_VAL(I2C_1)
static struct samd21_i2c_state samd21_i2c1;
#endif
#if MYNEWT_VAL(I2C_2)
static struct samd21_i2c_state samd21_i2c2;
#endif
#if MYNEWT_VAL(I2C_3)
static struct samd21_i2c_state samd21_i2c3;
#endif
#if MYNEWT_VAL(I2C_4)
static struct samd21_i2c_state samd21_i2c4;
#endif
#if MYNEWT_VAL(I2C_5)
static struct samd21_i2c_state samd21_i2c5;
#endif
struct samd21_i2c_state *samd21_hal_i2cs[HAL_SAMD21_I2C_MAX] = {
#if MYNEWT_VAL(I2C_0)
&samd21_i2c0,
#else
NULL,
#endif
#if MYNEWT_VAL(I2C_1)
&samd21_i2c1,
#else
NULL,
#endif
#if MYNEWT_VAL(I2C_2)
&samd21_i2c2,
#else
NULL,
#endif
#if MYNEWT_VAL(I2C_3)
&samd21_i2c3,
#else
NULL,
#endif
#if MYNEWT_VAL(I2C_4)
&samd21_i2c4,
#else
NULL,
#endif
#if MYNEWT_VAL(I2C_5)
&samd21_i2c5,
#else
NULL,
#endif
};
#define SAMD21_I2C_RESOLVE(__n, __v) \
if ((__n) >= HAL_SAMD21_I2C_MAX || !samd21_hal_i2cs[(__n)]) { \
rc = EINVAL; \
goto err; \
} \
(__v) = samd21_hal_i2cs[(__n)];
int
hal_i2c_init(uint8_t i2c_num, void *usercfg)
{
struct samd21_i2c_state *i2c;
enum status_code status;
struct i2c_master_config cfg;
int rc;
SAMD21_I2C_RESOLVE(i2c_num, i2c);
assert(usercfg != NULL);
i2c->hw = samd21_sercom(i2c_num);
if (i2c->hw == NULL) {
rc = EINVAL;
goto err;
}
i2c->pconfig = (struct samd21_i2c_config *)usercfg;
i2c_master_get_config_defaults(&cfg);
cfg.pinmux_pad0 = i2c->pconfig->pad0_pinmux;
cfg.pinmux_pad1 = i2c->pconfig->pad1_pinmux;
status = i2c_master_init(&i2c->module, i2c->hw, &cfg);
if (status != STATUS_OK) {
rc = (int)status;
goto err;
}
i2c_master_enable(&i2c->module);
return (0);
err:
return (rc);
}
int
hal_i2c_master_write(uint8_t i2c_num, struct hal_i2c_master_data *ppkt,
uint32_t os_ticks, uint8_t last_op)
{
struct samd21_i2c_state *i2c;
struct i2c_master_packet pkt;
enum status_code status;
int rc;
SAMD21_I2C_RESOLVE(i2c_num, i2c);
memset(&pkt, 0, sizeof(pkt));
pkt.address = ppkt->address;
pkt.data_length = ppkt->len;
pkt.data = ppkt->buffer;
if (last_op) {
status = i2c_master_write_packet_wait(&i2c->module, &pkt);
} else {
status = i2c_master_write_packet_wait_no_stop(&i2c->module, &pkt);
}
if (status != STATUS_OK) {
rc = (int) status;
goto err;
}
return (0);
err:
return (rc);
}
int
hal_i2c_master_read(uint8_t i2c_num, struct hal_i2c_master_data *ppkt,
uint32_t os_ticks, uint8_t last_op)
{
struct samd21_i2c_state *i2c;
struct i2c_master_packet pkt;
enum status_code status;
int rc;
SAMD21_I2C_RESOLVE(i2c_num, i2c);
memset(&pkt, 0, sizeof(pkt));
pkt.address = ppkt->address;
pkt.data_length = ppkt->len;
pkt.data = ppkt->buffer;
if (last_op) {
status = i2c_master_read_packet_wait(&i2c->module, &pkt);
} else {
status = i2c_master_read_packet_wait_no_stop(&i2c->module, &pkt);
}
if (status != STATUS_OK) {
rc = (int)status;
goto err;
}
return (0);
err:
return (rc);
}
int
hal_i2c_master_probe(uint8_t i2c_num, uint8_t address, uint32_t os_ticks)
{
struct samd21_i2c_state *i2c;
struct i2c_master_packet pkt;
enum status_code status;
int rc;
uint8_t buf;
SAMD21_I2C_RESOLVE(i2c_num, i2c);
memset(&pkt, 0, sizeof(pkt));
pkt.address = address;
pkt.data_length = 0;
pkt.data = &buf;
status = i2c_master_read_packet_wait(&i2c->module, &pkt);
if (status != STATUS_OK) {
rc = (int)status;
goto err;
}
return (0);
err:
return (rc);
}