/**************************************************************************** * drivers/regmap/regmap.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you 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. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include "internal.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ #define REGMAP_ALIGNED(n, a) (((uint32_t)(n) & ((a) - 1)) == 0) #define REGMAP_DIVUP(n,d) (((n) + (d) - 1) / (d)) #define REGMAP_DEFAULT_BIT 8 /**************************************************************************** * Private Functions ****************************************************************************/ static void regmap_lock_unlock_none(FAR void *context) { } static void regmap_lock_mutex(FAR void *context) { FAR struct regmap_s *map = context; nxmutex_lock(&map->mutex[0]); } static void regmap_unlock_mutex(FAR void *context) { FAR struct regmap_s *map = context; nxmutex_unlock(&map->mutex[0]); } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: regmap_init * * Description: * Initialize the internal configuration of regmap. The first parameter * must be the handle of the bus, and the second parameter is the * configuration parameter of the bus. Finally, these two parameters will * be transparent to the corresponding bus. * * Input Parameters: * dev - device handle. * bus - device configuration. * config - regmap configuration. * * Returned Value: * Description of the value returned by this function (if any), * including an enumeration of all possible error values. * * Assumptions/Limitations: * None. * ****************************************************************************/ FAR struct regmap_s *regmap_init(FAR struct regmap_bus_s *bus, FAR const struct regmap_config_s *config) { FAR struct regmap_s *map; if (config == NULL || bus == NULL) { return NULL; } if (config->disable_locking) { map = kmm_zalloc(sizeof(*map)); if (map == NULL) { return NULL; } map->lock = regmap_lock_unlock_none; map->unlock = regmap_lock_unlock_none; } else { map = kmm_zalloc(sizeof(*map) + sizeof(mutex_t)); if (map == NULL) { return NULL; } nxmutex_init(&map->mutex[0]); map->lock = regmap_lock_mutex; map->unlock = regmap_unlock_mutex; } if (config->reg_stride != 0) { map->reg_stride = config->reg_stride; } else { map->reg_stride = 1; } map->reg_bytes = REGMAP_DIVUP(config->reg_bits, REGMAP_DEFAULT_BIT); map->val_bytes = REGMAP_DIVUP(config->val_bits, REGMAP_DEFAULT_BIT); map->bus = bus; map->reg_read = bus->reg_read; map->reg_write = bus->reg_write; map->read = bus->read; map->write = bus->write; return map; } /**************************************************************************** * Name: regmap_write * * Description: * Regmap write, called after initializing the regmap bus device. * the first parameter is regmap pointer. * * Input Parameters: * map - regmap handler, from regmap bus init function return. * reg - register address to be write. * val - write data. * * Returned Value: * Description of the value returned by this function (if any), * including an enumeration of all possible error values. * * Assumptions/Limitations: * None. * ****************************************************************************/ int regmap_write(FAR struct regmap_s *map, unsigned int reg, unsigned int val) { int ret; DEBUGASSERT(REGMAP_ALIGNED(reg, map->reg_stride)); map->lock(map); ret = map->reg_write(map->bus, reg, val); map->unlock(map); return ret; } /**************************************************************************** * Name: regmap_bulk_write * * Description: * Regmap bulk write, called after initializing the regmap bus device. * the first parameter is regmap pointer. * * Input Parameters: * map - regmap handler, from regmap bus init function return. * reg - register address to be write. * val - write data buffer. * val_count - write data buffer size. * * Returned Value: * Description of the value returned by this function (if any), * including an enumeration of all possible error values. * * Assumptions/Limitations: * None. * ****************************************************************************/ int regmap_bulk_write(FAR struct regmap_s *map, unsigned int reg, FAR const void *val, unsigned int val_count) { size_t val_bytes = map->val_bytes; int ret = -ENOSYS; unsigned int ival; FAR uint8_t *ptr; int i; DEBUGASSERT(REGMAP_ALIGNED(reg, map->reg_stride)); map->lock(map); if (map->write != NULL) { ret = map->write(map->bus, val, val_bytes * val_count); goto out; } for (i = 0; i < val_count; i++) { ptr = (FAR uint8_t *)val + (i * val_bytes); switch (val_bytes) { case 1: ival = *(FAR uint8_t *)ptr; break; case 2: ival = *(FAR uint16_t *)ptr; break; case 4: ival = *(FAR uint32_t *)ptr; break; default: ret = -EINVAL; goto out; } ret = map->reg_write(map->bus, reg + (i * map->reg_stride), ival); if (ret < 0) { break; } } out: map->unlock(map); return ret; } /**************************************************************************** * Name: regmap_read * * Description: * Regmap read, called after initializing the regmap bus device. * the first parameter is regmap pointer. * * Input Parameters: * map - regmap handler, from regmap bus init function return. * reg - register address to be read. * val - read data buffer. * * Returned Value: * Description of the value returned by this function (if any), * including an enumeration of all possible error values. * * Assumptions/Limitations: * None. * ****************************************************************************/ int regmap_read(FAR struct regmap_s *map, unsigned int reg, FAR void *val) { int ret; DEBUGASSERT(REGMAP_ALIGNED(reg, map->reg_stride)); map->lock(map); ret = map->reg_read(map->bus, reg, val); map->unlock(map); return ret; } /**************************************************************************** * Name: regmap_bulk_read * * Description: * Regmap bulk read, called after initializing the regmap bus device. * the first parameter is regmap pointer. * * Input Parameters: * map - regmap handler, from regmap bus init function return. * reg - register address to be read. * val - read data buffer. * val_count - read data buffer size. * * Returned Value: * Description of the value returned by this function (if any), * including an enumeration of all possible error values. * * Assumptions/Limitations: * None. * ****************************************************************************/ int regmap_bulk_read(FAR struct regmap_s *map, unsigned int reg, FAR void *val, unsigned int val_count) { FAR uint32_t *u32 = val; FAR uint16_t *u16 = val; FAR uint8_t *u8 = val; unsigned int ival; int ret = -ENOSYS; int i; DEBUGASSERT(REGMAP_ALIGNED(reg, map->reg_stride)); map->lock(map); if (map->read != NULL) { ret = map->read(map->bus, ®, map->reg_bytes, val, val_count); } else { for (i = 0; i < val_count; i++) { ret = map->reg_read(map->bus, reg + (i * map->reg_stride), &ival); if (ret < 0) { break; } switch (map->val_bytes) { case 4: u32[i] = ival; break; case 2: u16[i] = ival; break; case 1: u8[i] = ival; break; default: map->unlock(map); return -EINVAL; } } } map->unlock(map); return ret; } /**************************************************************************** * Name: regmap_exit * * Description: * Free a previously allocated register map * * Input Parameters: * map - regmap handler, from regmap bus init function return. * * Assumptions/Limitations: * None. ****************************************************************************/ void regmap_exit(FAR struct regmap_s *map) { if (!map->disable_locking) { nxmutex_destroy(&map->mutex[0]); } if (map->bus->exit != NULL) { map->bus->exit(map->bus); } kmm_free(map->bus); kmm_free(map); }