Code relocation

Signed-off-by: YOUR_NAME <guodongqi2@huawei.com>
This commit is contained in:
YOUR_NAME
2021-11-09 19:26:07 +08:00
parent c6c55bbc69
commit 8bcb63e79d
47 changed files with 3549 additions and 0 deletions
+38
View File
@@ -0,0 +1,38 @@
root {
device_info {
platform :: host {
hostName = "platform_host";
priority = 50;
device_gpio :: device {
device1 :: deviceNode {
policy = 2;
priority = 10;
permission = 0660;
moduleName = "GPIO_SAMPLE";
serviceName = "GPIO_SAMPLE";
deviceMatchAttr = "sample_gpio";
}
}
device_uart :: device {
device5 :: deviceNode {
policy = 2;
priority = 10;
permission = 0660;
moduleName = "UART_SAMPLE";
serviceName = "HDF_PLATFORM_UART_5";
deviceMatchAttr = "sample_uart_5";
}
}
device_spi :: device {
device3 :: deviceNode {
policy = 2;
priority = 60;
permission = 0660;
moduleName = "SPI_SAMPLE";
serviceName = "HDF_PLATFORM_SPI_3";
deviceMatchAttr = "sample_spi_3";
}
}
}
}
}
+15
View File
@@ -0,0 +1,15 @@
root {
platform {
gpio_config {
gpio_sample {
match_attr = "sample_gpio";
groupNum = 12;
bitNum = 8;
regBase = 0x120d0000;
regStep = 0x1000;
irqStart = 48;
irqShare = 0;
}
}
}
}
+19
View File
@@ -0,0 +1,19 @@
root {
platform {
spi_config {
spi_sample {
serviceName = "SPI_SAMPLE";
match_attr = "sample_spi_3";
transferMode = 0;
busNum = 0;
clkRate = 100000000;
bitsPerWord = 8;
mode = 19;
speed = 2000000;
fifoSize = 256;
numCs = 1;
regBase = 0x120c0000;
}
}
}
}
+15
View File
@@ -0,0 +1,15 @@
root {
platform {
uart_sample {
num = 5;
base = 0x120a0000; // UART base register address
irqNum = 38;
baudrate = 115200;
uartClk = 24000000; // 24 M
wlen = 0x60; // 8 bit width
parity = 0;
stopBit = 0;
match_attr = "sample_uart_5";
}
}
}
+11
View File
@@ -0,0 +1,11 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
#
# HDF is dual licensed: you can use it either under the terms of
# the GPL, or the BSD license, at your option.
# See the LICENSE file in the root of this repository for complete details.
import("//build/lite/config/component/lite_component.gni")
lite_component("hello_gpio_sample") {
features = [ "dispatch:hello_gpio_dispatch" ]
}
+12
View File
@@ -0,0 +1,12 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
#
# HDF is dual licensed: you can use it either under the terms of
# the GPL, or the BSD license, at your option.
# See the LICENSE file in the root of this repository for complete details.
config DRIVERS_HDF_PLATFORM_GPIO_SAMPLE
bool "Enable HDF platform gpio sample driver"
default n
depends on DRIVERS_HDF_PLATFORM
help
Answer Y to enable HDF platform gpio sample driver.
+45
View File
@@ -0,0 +1,45 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
#
# HDF is dual licensed: you can use it either under the terms of
# the GPL, or the BSD license, at your option.
# See the LICENSE file in the root of this repository for complete details.
HDF_FRAMEWORKS = "//drivers/framework"
executable("hello_gpio_dispatch") {
sources = [
"gpio_if.c",
"hello_gpio_dispatch.c",
]
include_dirs = [
"$HDF_FRAMEWORKS/ability/sbuf/include",
"$HDF_FRAMEWORKS/core/shared/include",
"$HDF_FRAMEWORKS/core/host/include",
"$HDF_FRAMEWORKS/core/master/include",
"$HDF_FRAMEWORKS/include/core",
"$HDF_FRAMEWORKS/include/utils",
"$HDF_FRAMEWORKS/utils/include",
"$HDF_FRAMEWORKS/include/osal",
"//drivers/adapter/uhdf/posix/include",
"//third_party/bounds_checking_function/include",
"//base/hiviewdfx/hilog_lite/interfaces/native/innerkits",
"//drivers/framework/support/platform/include/gpio",
]
deps = [
"//base/hiviewdfx/hilog_lite/frameworks/featured:hilog_shared",
"//drivers/adapter/uhdf/manager:hdf_core",
"//drivers/adapter/uhdf/posix:hdf_posix_osal",
]
public_deps = [ "//third_party/bounds_checking_function:libsec_shared" ]
defines = [ "__USER__" ]
cflags = [
"-Wall",
"-Wextra",
"-Wno-format",
"-Wno-format-extra-args",
]
}
+128
View File
@@ -0,0 +1,128 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "gpio_if.h"
#include "hdf_log.h"
#include "hdf_io_service_if.h"
#define HDF_LOG_TAG gpio_if
static struct HdfIoService *GetIoService()
{
static struct HdfIoService *ioService = NULL;
if (ioService != NULL) {
return ioService;
}
ioService = HdfIoServiceBind(GPIO_SERVICE_NAME);
if (ioService == NULL) {
HDF_LOGE("Failed to get service %s", GPIO_SERVICE_NAME);
}
return ioService;
}
static int32_t GpioOperate(enum GpioOps ops, uint16_t gpio, uint16_t val)
{
int ret = HDF_FAILURE;
struct HdfIoService *service = GetIoService();
if (service == NULL) {
return ret;
}
struct HdfSBuf *data = HdfSBufObtainDefaultSize();
if (data == NULL) {
HDF_LOGE("Failed to obtain sBuf");
return ret;
}
if (!HdfSbufWriteUint16(data, gpio) || !HdfSbufWriteUint16(data, val)) {
HDF_LOGE("Failed to write sBuf");
HdfSBufRecycle(data);
return HDF_FAILURE;
}
ret = service->dispatcher->Dispatch(&service->object, ops, data, NULL);
if (ret != HDF_SUCCESS) {
HDF_LOGE("Failed to send service call, ret: %d", ret);
}
HdfSBufRecycle(data);
return ret;
}
static int32_t GpioQuery(enum GpioOps ops, uint16_t gpio, uint16_t *val)
{
int ret = HDF_FAILURE;
struct HdfIoService *service = GetIoService();
if (service == NULL) {
return ret;
}
struct HdfSBuf *data = HdfSBufObtainDefaultSize();
struct HdfSBuf *reply = HdfSBufObtainDefaultSize();
if (data == NULL || reply == NULL) {
HDF_LOGE("Failed to obtain sBuf");
return ret;
}
if (!HdfSbufWriteUint16(data, gpio)) {
HDF_LOGE("Failed to write data sBuf");
goto __ERR__;
}
ret = service->dispatcher->Dispatch(&service->object, ops, data, reply);
if (ret != HDF_SUCCESS) {
HDF_LOGE("Failed to send service call");
goto __ERR__;
}
if (!HdfSbufReadUint16(reply, val)) {
HDF_LOGE("Failed to read reply sBuf");
goto __ERR__;
}
goto __ERR__;
__ERR__:
HdfSBufRecycle(data);
HdfSBufRecycle(reply);
return ret;
}
int32_t GpioOpen()
{
struct HdfIoService *ioService = GetIoService();
if (ioService == NULL) {
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
int32_t GpioSetDir(uint16_t gpio, uint16_t dir)
{
return GpioOperate(GPIO_OPS_SET_DIR, gpio, dir);
}
int32_t GpioGetDir(uint16_t gpio, uint16_t *dir)
{
return GpioQuery(GPIO_OPS_GET_DIR, gpio, dir);
}
int32_t GpioWrite(uint16_t gpio, uint16_t val)
{
return GpioOperate(GPIO_OPS_WRITE, gpio, val);
}
int32_t GpioRead(uint16_t gpio, uint16_t *val)
{
return GpioQuery(GPIO_OPS_READ, gpio, val);
}
int32_t GpioClose()
{
struct HdfIoService *ioService = GetIoService();
if (ioService == NULL) {
return HDF_FAILURE;
}
HdfIoServiceRecycle(ioService);
return HDF_SUCCESS;
}
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef GPIO_IF_H
#define GPIO_IF_H
#include <stdint.h>
#define GPIO_SERVICE_NAME "GPIO_SAMPLE"
enum GpioValue {
GPIO_VAL_LOW = 0,
GPIO_VAL_HIGH = 1,
GPIO_VAL_ERR,
};
enum GpioDirType {
GPIO_DIR_IN = 0,
GPIO_DIR_OUT = 1,
GPIO_DIR_ERR,
};
enum GpioOps {
GPIO_OPS_SET_DIR = 1,
GPIO_OPS_GET_DIR,
GPIO_OPS_WRITE,
GPIO_OPS_READ
};
int32_t GpioOpen();
int32_t GpioClose();
int32_t GpioSetDir(uint16_t gpio, uint16_t dir);
int32_t GpioGetDir(uint16_t gpio, uint16_t *dir);
int32_t GpioWrite(uint16_t gpio, uint16_t val);
int32_t GpioRead(uint16_t gpio, uint16_t *val);
#endif // GPIO_IF_H
+46
View File
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "gpio_if.h"
#include "hdf_log.h"
#include "hdf_base.h"
#define HDF_LOG_TAG hello_gpio_dispatch
#define GPIO_PIN 11
int main()
{
uint16_t dir;
uint16_t val;
if (GpioOpen() != HDF_SUCCESS) {
HDF_LOGE("%s: GpioOpen failed", __func__);
return HDF_FAILURE;
}
if (GpioSetDir(GPIO_PIN, GPIO_DIR_IN) != HDF_SUCCESS) {
HDF_LOGE("%s: GpioSetDir failed, gpio %u, dir %u", __func__, GPIO_PIN, GPIO_DIR_IN);
return HDF_FAILURE;
}
if (GpioWrite(GPIO_PIN, GPIO_VAL_HIGH) != HDF_SUCCESS) {
HDF_LOGE("%s: GpioWrite failed, gpio %u, val %u", __func__, GPIO_PIN, GPIO_VAL_HIGH);
return HDF_FAILURE;
}
if (GpioGetDir(GPIO_PIN, &dir) != HDF_SUCCESS) {
HDF_LOGE("%s: GpioGetDir failed, gpio %u", __func__, GPIO_PIN);
return HDF_FAILURE;
}
if (GpioRead(GPIO_PIN, &val) != HDF_SUCCESS) {
HDF_LOGE("%s: GpioRead failed, gpio %u", __func__, GPIO_PIN);
return HDF_FAILURE;
}
if (GpioClose() != HDF_SUCCESS) {
HDF_LOGE("%s: GpioClose failed", __func__);
return HDF_FAILURE;
}
HDF_LOGD("GPIO %u direction is set to %u, value is set to %u", GPIO_PIN, dir, val);
return HDF_SUCCESS;
}
+23
View File
@@ -0,0 +1,23 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef GPIO_DISPATCH_SAMPLE_H
#define GPIO_DISPATCH_SAMPLE_H
#include "gpio_pl061_sample.h"
enum GpioOps {
GPIO_OPS_SET_DIR = 1,
GPIO_OPS_GET_DIR,
GPIO_OPS_WRITE,
GPIO_OPS_READ
};
int32_t SampleGpioDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply);
#endif // GPIO_DISPATCH_SAMPLE_H
+75
View File
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef GPIO_PL061_SAMPLE_H
#define GPIO_PL061_SAMPLE_H
#include "gpio_core.h"
#include "gpio_if.h"
#include "osal.h"
#define GROUP_MAX 32
#define BIT_MAX 16
#define GPIO_DATA(base, bit) ((base) + 0x000 + (1 << ((bit) + 2)))
#define GPIO_DIR(base) ((base) + 0x400)
#define GPIO_IS(base) ((base) + 0x404)
#define GPIO_IBE(base) ((base) + 0x408)
#define GPIO_IEV(base) ((base) + 0x40C)
#define GPIO_IE(base) ((base) + 0x410)
#define GPIO_RIS(base) ((base) + 0x414)
#define GPIO_MIS(base) ((base) + 0x418)
#define GPIO_IC(base) ((base) + 0x41C)
struct GpioGroup {
volatile unsigned char *regBase;
unsigned int index;
OsalSpinlock lock;
};
struct Pl061GpioCntlr {
struct GpioCntlr cntlr;
volatile unsigned char *regBase;
uint32_t phyBase;
uint32_t regStep;
uint32_t irqStart;
uint16_t groupNum;
uint16_t bitNum;
uint8_t irqShare;
struct GpioGroup *groups;
};
static struct Pl061GpioCntlr g_samplePl061GpioCntlr = {
.groups = NULL,
.groupNum = GROUP_MAX,
.bitNum = BIT_MAX,
};
static inline struct Pl061GpioCntlr *ToPl061GpioCntlr(struct GpioCntlr *cntlr)
{
return (struct Pl061GpioCntlr *)cntlr;
}
static inline uint16_t Pl061ToGroupNum(uint16_t gpio)
{
return (uint16_t)(gpio / g_samplePl061GpioCntlr.bitNum);
}
static inline uint16_t Pl061ToBitNum(uint16_t gpio)
{
return (uint16_t)(gpio % g_samplePl061GpioCntlr.bitNum);
}
static inline uint16_t Pl061ToGpioNum(uint16_t group, uint16_t bit)
{
return (uint16_t)(group * g_samplePl061GpioCntlr.bitNum + bit);
}
int32_t Pl061GetGroupByGpioNum(struct GpioCntlr *cntlr, uint16_t gpio,
struct GpioGroup **group);
#endif // GPIO_PL061_SAMPLE_H
+23
View File
@@ -0,0 +1,23 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
#
# HDF is dual licensed: you can use it either under the terms of
# the GPL, or the BSD license, at your option.
# See the LICENSE file in the root of this repository for complete details.
import("//drivers/adapter/khdf/liteos/hdf.gni")
module_switch = defined(LOSCFG_DRIVERS_HDF_PLATFORM_GPIO_SAMPLE)
module_name = "hdf_gpio_sample"
hdf_driver(module_name) {
FRAMEWORK_GPIO_ROOT = "//drivers/framework/sample/platform/gpio/src"
sources = [
"$FRAMEWORK_GPIO_ROOT/gpio_dispatch_sample.c",
"$FRAMEWORK_GPIO_ROOT/gpio_pl061_sample.c",
"$FRAMEWORK_GPIO_ROOT/gpio_sample.c",
]
include_dirs = [
"//drivers/framework/sample/platform/gpio/include/",
"//drivers/framework/support/platform/include/gpio",
]
}
+119
View File
@@ -0,0 +1,119 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "gpio_dispatch_sample.h"
#define HDF_LOG_TAG gpio_dispatch_sample
static int32_t SampleGpioSetDir(struct GpioCntlr *cntlr, struct HdfSBuf *data)
{
uint16_t gpio;
uint16_t dir;
if (!HdfSbufReadUint16(data, &gpio) || !HdfSbufReadUint16(data, &dir)) {
HDF_LOGE("%s: HdfSbufReadUint16 failed", __func__);
return HDF_ERR_INVALID_PARAM;
}
if (cntlr->ops->setDir == NULL) {
HDF_LOGE("%s: cntlr->ops->setDir is NULL", __func__);
return HDF_DEV_ERR_OP;
}
return cntlr->ops->setDir(cntlr, gpio, dir);
}
static int32_t SampleGpioGetDir(struct GpioCntlr *cntlr, struct HdfSBuf *data, struct HdfSBuf *reply)
{
int32_t ret;
uint16_t gpio;
uint16_t dir;
if (!HdfSbufReadUint16(data, &gpio)) {
HDF_LOGE("%s: HdfSbufReadUint16 failed", __func__);
return HDF_ERR_INVALID_PARAM;
}
if (cntlr->ops->getDir == NULL) {
HDF_LOGE("%s: cntlr->ops->getDir is NULL", __func__);
return HDF_DEV_ERR_OP;
}
ret = cntlr->ops->getDir(cntlr, gpio, &dir);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: cntlr->ops->getDir failed, ret: %d", __func__, ret);
return ret;
}
if (!HdfSbufWriteUint16(reply, dir)) {
HDF_LOGE("%s: HdfSbufWriteUint16 failed", __func__);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static int32_t SampleGpioWrite(struct GpioCntlr *cntlr, struct HdfSBuf *data)
{
uint16_t gpio;
uint16_t val;
if (!HdfSbufReadUint16(data, &gpio) || !HdfSbufReadUint16(data, &val)) {
HDF_LOGE("%s: HdfSbufReadUint16 failed", __func__);
return HDF_ERR_INVALID_PARAM;
}
if (cntlr->ops->write == NULL) {
HDF_LOGE("%s: cntlr->ops->read is NULL", __func__);
return HDF_DEV_ERR_OP;
}
return cntlr->ops->write(cntlr, gpio, val);
}
static int32_t SampleGpioRead(struct GpioCntlr *cntlr, struct HdfSBuf *data, struct HdfSBuf *reply)
{
int32_t ret;
uint16_t gpio;
uint16_t val;
if (!HdfSbufReadUint16(data, &gpio)) {
HDF_LOGE("%s: HdfSbufReadUint16 failed", __func__);
return HDF_ERR_INVALID_PARAM;
}
if (cntlr->ops->read == NULL) {
HDF_LOGE("%s: cntlr->ops->read is NULL", __func__);
return HDF_DEV_ERR_OP;
}
ret = cntlr->ops->read(cntlr, gpio, &val);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: cntlr->ops->read failed, ret: %d", __func__, ret);
return ret;
}
if (!HdfSbufWriteUint16(reply, val)) {
HDF_LOGE("%s: HdfSbufWriteUint16 failed", __func__);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
int32_t SampleGpioDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply)
{
if (client == NULL || client->device == NULL) {
HDF_LOGE("%s: client or client->device is NULL", __func__);
return HDF_ERR_INVALID_PARAM;
}
struct GpioCntlr *cntlr = (struct GpioCntlr *)client->device->service;
if (cntlr == NULL || cntlr->ops == NULL) {
HDF_LOGE("%s: cntlr or cntlr->ops is NULL", __func__);
return HDF_ERR_INVALID_PARAM;
}
switch (cmdId) {
case GPIO_OPS_SET_DIR:
return SampleGpioSetDir(cntlr, data);
case GPIO_OPS_GET_DIR:
return SampleGpioGetDir(cntlr, data, reply);
case GPIO_OPS_WRITE:
return SampleGpioWrite(cntlr, data);
case GPIO_OPS_READ:
return SampleGpioRead(cntlr, data, reply);
default:
HDF_LOGE("%s: invalid cmdId %d", __func__, cmdId);
return HDF_FAILURE;
}
}
+30
View File
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "gpio_pl061_sample.h"
#include "osal_irq.h"
#define HDF_LOG_TAG gpio_pl061_sample
int32_t Pl061GetGroupByGpioNum(struct GpioCntlr *cntlr, uint16_t gpio, struct GpioGroup **group)
{
struct Pl061GpioCntlr *pl061 = NULL;
uint16_t groupIndex = Pl061ToGroupNum(gpio);
if (cntlr == NULL) {
HDF_LOGE("%s: cntlr is NULL", __func__);
return HDF_ERR_INVALID_OBJECT;
}
pl061 = ToPl061GpioCntlr(cntlr);
if (groupIndex >= pl061->groupNum) {
HDF_LOGE("%s: err group index:%u", __func__, groupIndex);
return HDF_ERR_INVALID_PARAM;
}
*group = &pl061->groups[groupIndex];
return HDF_SUCCESS;
}
+359
View File
@@ -0,0 +1,359 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "gpio_dispatch_sample.h"
#include "gpio_pl061_sample.h"
#include "device_resource_if.h"
#include "hdf_device_desc.h"
#include "gpio_if.h"
#include "osal.h"
#include "osal_io.h"
#include "gpio_core.h"
#define HDF_LOG_TAG gpio_sample
/* HdfDriverEntry hook function prototypes */
static int32_t SampleGpioDriverBind(struct HdfDeviceObject *device);
static int32_t SampleGpioDriverInit(struct HdfDeviceObject *device);
static void SampleGpioDriverRelease(struct HdfDeviceObject *device);
/* HdfDriverEntry definition */
struct HdfDriverEntry g_sampleGpioDriverEntry = {
.moduleVersion = 1,
.moduleName = "GPIO_SAMPLE",
.Bind = SampleGpioDriverBind,
.Init = SampleGpioDriverInit,
.Release = SampleGpioDriverRelease,
};
/* Init HdfDriverEntry */
HDF_INIT(g_sampleGpioDriverEntry);
/* GPIO function prototypes */
static int32_t SampleGpioWrite(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t val);
static int32_t SampleGpioRead(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t *val);
static int32_t SampleGpioSetDirection(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t dir);
static int32_t SampleGpioGetDirection(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t *dir);
/* GpioMethod definition */
struct GpioMethod g_sampleGpioMethod = {
.request = NULL,
.release = NULL,
.write = SampleGpioWrite,
.read = SampleGpioRead,
.setDir = SampleGpioSetDirection,
.getDir = SampleGpioGetDirection,
.toIrq = NULL,
.setIrq = NULL,
.unsetIrq = NULL,
.enableIrq = NULL,
.disableIrq = NULL,
};
/* Private function prototypes */
/* Read GPIO device resource */
static int32_t GetGpioDeviceResource(struct Pl061GpioCntlr *cntlr, const struct DeviceResourceNode *node);
/* Init GPIO controller memory */
static int32_t InitGpioCntlrMem(struct Pl061GpioCntlr *cntlr);
/* Release GPIO controller memory */
static void ReleaseGpioCntlrMem(struct Pl061GpioCntlr *cntlr);
/* HdfDriverEntry hook function implementations */
static int32_t SampleGpioDriverBind(struct HdfDeviceObject *device)
{
HDF_LOGD("%s: Enter", __func__);
struct Pl061GpioCntlr *pl061Cntlr = &g_samplePl061GpioCntlr;
pl061Cntlr->cntlr.device = device;
device->service = &(pl061Cntlr->cntlr.service);
pl061Cntlr->cntlr.device->service->Dispatch = SampleGpioDispatch;
return HDF_SUCCESS;
}
static int32_t SampleGpioDriverInit(struct HdfDeviceObject *device)
{
int32_t ret;
struct Pl061GpioCntlr *pl061Cntlr = &g_samplePl061GpioCntlr;
HDF_LOGD("%s: Enter", __func__);
if (device == NULL || device->property == NULL) {
HDF_LOGE("%s: device or property NULL!", __func__);
return HDF_ERR_INVALID_OBJECT;
}
ret = GetGpioDeviceResource(pl061Cntlr, device->property);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: get gpio device resource fail:%d", __func__, ret);
return ret;
}
if (pl061Cntlr->groupNum > GROUP_MAX || pl061Cntlr->groupNum <= 0 || pl061Cntlr->bitNum > BIT_MAX ||
pl061Cntlr->bitNum <= 0) {
HDF_LOGE("%s: invalid groupNum:%u or bitNum:%u", __func__, pl061Cntlr->groupNum,
pl061Cntlr->bitNum);
return HDF_ERR_INVALID_PARAM;
}
pl061Cntlr->regBase = OsalIoRemap(pl061Cntlr->phyBase, pl061Cntlr->groupNum * pl061Cntlr->regStep);
if (pl061Cntlr->regBase == NULL) {
HDF_LOGE("%s: err remap phy:0x%x", __func__, pl061Cntlr->phyBase);
return HDF_ERR_IO;
}
ret = InitGpioCntlrMem(pl061Cntlr);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: err init cntlr mem:%d", __func__, ret);
OsalIoUnmap((void *)pl061Cntlr->regBase);
pl061Cntlr->regBase = NULL;
return ret;
}
pl061Cntlr->cntlr.count = pl061Cntlr->groupNum * pl061Cntlr->bitNum;
pl061Cntlr->cntlr.priv = (void *)device->property;
pl061Cntlr->cntlr.ops = &g_sampleGpioMethod;
ret = GpioCntlrAdd(&pl061Cntlr->cntlr);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: err add controller: %d", __func__, ret);
return ret;
}
HDF_LOGI("%s: dev service:%s init success!", __func__, HdfDeviceGetServiceName(device));
return ret;
}
static void SampleGpioDriverRelease(struct HdfDeviceObject *device)
{
struct GpioCntlr *gpioCntlr = NULL;
struct Pl061GpioCntlr *pl061GpioCntlr = NULL;
HDF_LOGD("%s: Enter", __func__);
if (device == NULL) {
HDF_LOGE("%s: device is null!", __func__);
return;
}
gpioCntlr = GpioCntlrFromDevice(device);
if (gpioCntlr == NULL) {
HDF_LOGE("%s: no service bound!", __func__);
return;
}
GpioCntlrRemove(gpioCntlr);
pl061GpioCntlr = (struct Pl061GpioCntlr *)gpioCntlr;
ReleaseGpioCntlrMem(pl061GpioCntlr);
OsalIoUnmap((void *)pl061GpioCntlr->regBase);
pl061GpioCntlr->regBase = NULL;
}
/* Private function implementations */
static int32_t GetGpioDeviceResource(struct Pl061GpioCntlr *cntlr, const struct DeviceResourceNode *node)
{
int32_t ret;
struct DeviceResourceIface *dri = NULL;
dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
if (dri == NULL || dri->GetUint8 == NULL || dri->GetUint16 == NULL || dri->GetUint32 == NULL) {
HDF_LOGE("%s: invalid dri ops fail!", __func__);
return HDF_FAILURE;
}
ret = dri->GetUint32(node, "regBase", &cntlr->phyBase, 0);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: read regBase fail!", __func__);
return ret;
}
ret = dri->GetUint32(node, "regStep", &cntlr->regStep, 0);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: read regStep fail!", __func__);
return ret;
}
ret = dri->GetUint16(node, "groupNum", &cntlr->groupNum, 0);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: read groupNum fail!", __func__);
return ret;
}
ret = dri->GetUint16(node, "bitNum", &cntlr->bitNum, 0);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: read bitNum fail!", __func__);
return ret;
}
ret = dri->GetUint32(node, "irqStart", &cntlr->irqStart, 0);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: read irqStart fail!", __func__);
return ret;
}
ret = dri->GetUint8(node, "irqShare", &cntlr->irqShare, 0);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: read irqShare fail!", __func__);
return ret;
}
return HDF_SUCCESS;
}
static int32_t InitGpioCntlrMem(struct Pl061GpioCntlr *cntlr)
{
size_t groupMemSize;
struct GpioGroup *groups = NULL;
if (cntlr == NULL) {
return HDF_ERR_INVALID_PARAM;
}
groupMemSize = sizeof(struct GpioGroup) * cntlr->groupNum;
groups = (struct GpioGroup *)OsalMemCalloc(groupMemSize);
if (groups == NULL) {
return HDF_ERR_MALLOC_FAIL;
}
cntlr->groups = groups;
for (uint16_t i = 0; i < cntlr->groupNum; i++) {
groups[i].index = i;
groups[i].regBase = cntlr->regBase + (i * cntlr->regStep);
if (OsalSpinInit(&groups[i].lock) != HDF_SUCCESS) {
for (; i > 0; i--) {
(void)OsalSpinDestroy(&groups[i - 1].lock);
}
OsalMemFree(groups);
return HDF_FAILURE;
}
}
return HDF_SUCCESS;
}
static void ReleaseGpioCntlrMem(struct Pl061GpioCntlr *cntlr)
{
if (cntlr == NULL) {
return;
}
if (cntlr->groups != NULL) {
for (uint16_t i = 0; i < cntlr->groupNum; i++) {
(void)OsalSpinDestroy(&cntlr->groups[i].lock);
}
OsalMemFree(cntlr->groups);
cntlr->groups = NULL;
}
}
/* GPIO function implementations */
static int32_t SampleGpioWrite(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t val)
{
HDF_LOGD("%s: Enter", __func__);
int32_t ret;
uint32_t irqSave;
unsigned int valCur;
unsigned int bitNum = Pl061ToBitNum(gpio);
volatile unsigned char *addr = NULL;
struct GpioGroup *group = NULL;
ret = Pl061GetGroupByGpioNum(cntlr, gpio, &group);
if (ret != HDF_SUCCESS) {
return ret;
}
addr = GPIO_DATA(group->regBase, bitNum);
if (OsalSpinLockIrqSave(&group->lock, &irqSave) != HDF_SUCCESS) {
return HDF_ERR_DEVICE_BUSY;
}
valCur = OSAL_READL(addr);
if (val == GPIO_VAL_LOW) {
valCur &= ~(1 << bitNum);
} else {
valCur |= (1 << bitNum);
}
OSAL_WRITEL(valCur, addr);
(void)OsalSpinUnlockIrqRestore(&group->lock, &irqSave);
HDF_LOGD("%s: gpio:%u, val:%u", __func__, gpio, val);
return HDF_SUCCESS;
}
static int32_t SampleGpioRead(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t *val)
{
HDF_LOGD("%s: Enter", __func__);
int32_t ret;
unsigned int valCur;
volatile unsigned char *addr = NULL;
unsigned int bitNum = Pl061ToBitNum(gpio);
struct GpioGroup *group = NULL;
ret = Pl061GetGroupByGpioNum(cntlr, gpio, &group);
if (ret != HDF_SUCCESS) {
return ret;
}
addr = GPIO_DATA(group->regBase, bitNum);
valCur = OSAL_READL(addr);
if (valCur & (1 << bitNum)) {
*val = GPIO_VAL_HIGH;
} else {
*val = GPIO_VAL_LOW;
}
HDF_LOGD("%s: gpio:%u, val:%u", __func__, gpio, *val);
return HDF_SUCCESS;
}
static int32_t SampleGpioSetDirection(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t dir)
{
HDF_LOGD("%s: Enter", __func__);
int32_t ret;
uint32_t irqSave;
unsigned int val;
volatile unsigned char *addr = NULL;
unsigned int bitNum = Pl061ToBitNum(gpio);
struct GpioGroup *group = NULL;
HDF_LOGD("%s: gpio:%u, dir:%d", __func__, gpio, dir);
ret = Pl061GetGroupByGpioNum(cntlr, gpio, &group);
if (ret != HDF_SUCCESS) {
return ret;
}
addr = GPIO_DIR(group->regBase);
if (OsalSpinLockIrqSave(&group->lock, &irqSave) != HDF_SUCCESS) {
return HDF_ERR_DEVICE_BUSY;
}
val = OSAL_READL(addr);
if (dir == GPIO_DIR_IN) {
val &= ~(1 << bitNum);
} else if (dir == GPIO_DIR_OUT) {
val |= 1 << bitNum;
}
OSAL_WRITEL(val, addr);
(void)OsalSpinUnlockIrqRestore(&group->lock, &irqSave);
return HDF_SUCCESS;
}
static int32_t SampleGpioGetDirection(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t *dir)
{
HDF_LOGD("%s: Enter", __func__);
int32_t ret;
unsigned int val;
volatile unsigned char *addr = NULL;
unsigned int bitNum = Pl061ToBitNum(gpio);
struct GpioGroup *group = NULL;
HDF_LOGD("%s: gpio:%u, dir:%p", __func__, gpio, dir);
ret = Pl061GetGroupByGpioNum(cntlr, gpio, &group);
if (ret != HDF_SUCCESS) {
return ret;
}
addr = GPIO_DIR(group->regBase);
val = OSAL_READL(addr);
if (val & (1 << bitNum)) {
*dir = GPIO_DIR_OUT;
} else {
*dir = GPIO_DIR_IN;
}
return HDF_SUCCESS;
}
+11
View File
@@ -0,0 +1,11 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
#
# HDF is dual licensed: you can use it either under the terms of
# the GPL, or the BSD license, at your option.
# See the LICENSE file in the root of this repository for complete details.
import("//build/lite/config/component/lite_component.gni")
lite_component("hello_spi_sample") {
features = [ "dispatch:hello_spi_dispatch" ]
}
+12
View File
@@ -0,0 +1,12 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
#
# HDF is dual licensed: you can use it either under the terms of
# the GPL, or the BSD license, at your option.
# See the LICENSE file in the root of this repository for complete details.
config DRIVERS_HDF_PLATFORM_SPI_SAMPLE
bool "Enable HDF platform spi sample driver"
default n
depends on DRIVERS_HDF_PLATFORM
help
Answer Y to enable HDF platform spi sample driver.
+45
View File
@@ -0,0 +1,45 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
#
# HDF is dual licensed: you can use it either under the terms of
# the GPL, or the BSD license, at your option.
# See the LICENSE file in the root of this repository for complete details.
HDF_FRAMEWORKS = "//drivers/framework"
executable("hello_spi_dispatch") {
sources = [
"hello_spi_dispatch.c",
"spi_if.c",
]
include_dirs = [
"$HDF_FRAMEWORKS/ability/sbuf/include",
"$HDF_FRAMEWORKS/core/shared/include",
"$HDF_FRAMEWORKS/core/host/include",
"$HDF_FRAMEWORKS/core/master/include",
"$HDF_FRAMEWORKS/include/core",
"$HDF_FRAMEWORKS/include/platform",
"$HDF_FRAMEWORKS/include/utils",
"$HDF_FRAMEWORKS/utils/include",
"$HDF_FRAMEWORKS/include/osal",
"//drivers/adapter/uhdf/posix/include",
"//third_party/bounds_checking_function/include",
"//base/hiviewdfx/hilog_lite/interfaces/native/innerkits",
]
deps = [
"//base/hiviewdfx/hilog_lite/frameworks/featured:hilog_shared",
"//drivers/adapter/uhdf/manager:hdf_core",
"//drivers/adapter/uhdf/posix:hdf_posix_osal",
]
public_deps = [ "//third_party/bounds_checking_function:libsec_shared" ]
defines = [ "__USER__" ]
cflags = [
"-Wall",
"-Wextra",
"-Wno-format",
"-Wno-format-extra-args",
]
}
+43
View File
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "spi_if.h"
#include "hdf_log.h"
#define HDF_LOG_TAG hello_spi_dispatch
int main()
{
int32_t ret;
struct SpiDevInfo spiDevInfo; /* SPI device descriptor */
struct DevHandle *spiHandle = NULL; /* SPI device handle */
spiDevInfo.busNum = 3; /* SPI device bus number */
spiDevInfo.csNum = 0; /* SPI device CS number */
spiHandle = SpiOpen(&spiDevInfo);
if (spiHandle == NULL) {
HDF_LOGE("SpiOpen failed");
return HDF_FAILURE;
}
uint8_t wbuff[1] = {0x12};
uint8_t rbuff[1] = {0};
struct SpiMsg msg; /* Custom message to be transferred */
msg.wbuf = wbuff; /* Pointer to the data to write */
msg.rbuf = rbuff; /* Pointer to the data to read */
msg.len = 1; /* The length of the data to be read or written is 1 bits. */
msg.csChange = 1; /* Disable the CS before the next transfer. */
msg.delayUs = 0; /* No delay before the next transfer */
msg.speed = 115200; /* Speed of this transfer */
ret = SpiTransfer(spiHandle, &msg);
if (ret != HDF_SUCCESS) {
HDF_LOGE("SpiTransfer failed, ret %d", ret);
return ret;
}
SpiClose(spiHandle);
return ret;
}
+87
View File
@@ -0,0 +1,87 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "spi_if.h"
#include "osal_mem.h"
#include "hdf_io_service_if.h"
#include "hdf_log.h"
#include "securec.h"
#define HDF_LOG_TAG spi_if
DevHandle SpiOpen(const struct SpiDevInfo *info)
{
int32_t ret;
void *devHandle = NULL;
uint32_t port;
char *serviceName = NULL;
if (info == NULL) {
HDF_LOGW("info is NULL");
return NULL;
}
port = info->busNum;
serviceName = (char *)OsalMemCalloc(MAX_DEV_NAME_SIZE + 1);
if (serviceName == NULL) {
HDF_LOGE("Failed to OsalMemCalloc serviceName");
return NULL;
}
ret = snprintf_s(serviceName, MAX_DEV_NAME_SIZE + 1, MAX_DEV_NAME_SIZE, SPI_DEV_SERVICE_NAME_PREFIX, port);
if (ret < 0) {
HDF_LOGE("Failed to snprintf_s");
OsalMemFree(serviceName);
return NULL;
}
devHandle = (void *)HdfIoServiceBind(serviceName);
OsalMemFree(serviceName);
return devHandle;
}
void SpiClose(DevHandle handle)
{
if (handle == NULL) {
HDF_LOGW("handle is NULL");
return;
}
struct HdfIoService *service = (struct HdfIoService *)handle;
HdfIoServiceRecycle(service);
OsalMemFree(handle);
}
int32_t SpiTransfer(DevHandle handle, struct SpiMsg *msgs)
{
int32_t ret;
if (handle == NULL || msgs == NULL) {
HDF_LOGW("handle or msgs is NULL");
return HDF_ERR_INVALID_PARAM;
}
struct HdfIoService *service = (struct HdfIoService *)handle;
if (service->dispatcher == NULL || service->dispatcher->Dispatch == NULL) {
HDF_LOGE("service->dispatcher or service->dispatcher->Dispatch is NULL");
return HDF_FAILURE;
}
struct HdfSBuf *sBuf = HdfSBufObtainDefaultSize();
if (sBuf == NULL) {
HDF_LOGE("Failed to obtain sBuf");
return HDF_FAILURE;
}
if (!HdfSbufWriteBuffer(sBuf, msgs, sizeof(struct SpiMsg))) {
HDF_LOGE("Failed to write sbuf");
HdfSBufRecycle(sBuf);
return HDF_FAILURE;
}
ret = service->dispatcher->Dispatch(&service->object, SPI_TRANSFER, sBuf, NULL);
if (ret != HDF_SUCCESS) {
HDF_LOGE("Failed to send service call");
}
HdfSBufRecycle(sBuf);
return ret;
}
+39
View File
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef SPI_IF_H
#define SPI_IF_H
#include "hdf_platform.h"
#define SPI_DEV_SERVICE_NAME_PREFIX "HDF_PLATFORM_SPI_%u"
#define MAX_DEV_NAME_SIZE 32
struct SpiDevInfo {
uint32_t busNum;
uint32_t csNum;
};
struct SpiMsg {
uint8_t *wbuf;
uint8_t *rbuf;
uint32_t len;
uint32_t speed;
uint16_t delayUs;
uint8_t csChange;
};
enum {
SPI_TRANSFER = 1
};
DevHandle SpiOpen(const struct SpiDevInfo *info);
void SpiClose(DevHandle handle);
int32_t SpiTransfer(DevHandle handle, struct SpiMsg *msgs);
#endif // SPI_IF_H
+21
View File
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef SPI_DISPATCH_SAMPLE_H
#define SPI_DISPATCH_SAMPLE_H
#include "spi_pl022_sample.h"
#include "spi_core.h"
enum {
SPI_TRANSFER = 1
};
int32_t SampleSpiDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply);
#endif // SPI_DISPATCH_SAMPLE_H
+118
View File
@@ -0,0 +1,118 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef SPI_PL022_SAMPLE_H
#define SPI_PL022_SAMPLE_H
#include "spi_if.h"
#include "osal.h"
/* ********** spi reg offset define start *************** */
#define REG_SPI_PL022_CR0 0x00
#define SPI_PL022_CR0_SCR_SHIFT 8
#define SPI_PL022_CR0_SPH_SHIFT 7
#define SPI_PL022_CR0_SPO_SHIFT 6
#define SPI_PL022_CR0_FRF_SHIFT 4
#define SPI_PL022_CR0_DSS_SHIFT 0
#define SPI_PL022_CR0_SCR (0xff << 8) /* clkout=clk/(cpsdvsr*(scr+1)) */
#define SPI_PL022_CR0_SPH (0x1 << 7) /* spi phase */
#define SPI_PL022_CR0_SPO (0x1 << 6) /* spi clk polarity */
#define SPI_PL022_CR0_FRF (0x3 << 4) /* frame format set */
#define SPI_PL022_CR0_DSS (0xf << 0) /* data bits width */
#define REG_SPI_PL022_CR1 0x04
#define SPI_PL022_CR1_WAIT_EN_SHIFT 15
#define SPI_PL022_CR1_WAIT_VAL_SHIFT 8
#define SPI_PL022_CR1_ALT_SHIFT 6
#define SPI_PL022_CR1_BIG_END_SHIFT 4
#define SPI_PL022_CR1_MS_SHIFT 2
#define SPI_PL022_CR1_SSE_SHIFT 1
#define SPI_PL022_CR1_LBN_SHIFT 0
#define SPI_PL022_CR1_WAIT_EN (0x1 << 15)
#define SPI_PL022_CR1_WAIT_VAL (0x7f << 8)
/* alt mode:spi enable csn is select; spi disable csn is cancel */
#define SPI_PL022_CR1_ALT (0x1 << 6)
#define SPI_PL022_CR1_BIG_END (0x1 << 4) /* big end or little */
#define SPI_PL022_CR1_MS (0x1 << 2) /* cntlr-device mode */
#define SPI_PL022_CR1_SSE (0x1 << 1) /* spi enable set */
#define SPI_PL022_CR1_LBM (0x1 << 0) /* loopback mode */
#define REG_SPI_PL022_DR 0x08
#define REG_SPI_PL022_SR 0x0c
#define SPI_PL022_SR_BSY_SHIFT 4
#define SPI_PL022_SR_RFF_SHIFT 3
#define SPI_PL022_SR_RNE_SHIFT 2
#define SPI_PL022_SR_TNF_SHIFT 1
#define SPI_PL022_SR_TFE_SHIFT 0
#define SPI_PL022_SR_BSY (0x1 << 4) /* spi busy flag */
#define SPI_PL022_SR_RFF (0x1 << 3) /* Whether to send fifo is full */
#define SPI_PL022_SR_RNE (0x1 << 2) /* Whether to send fifo is no empty */
#define SPI_PL022_SR_TNF (0x1 << 1) /* Whether to send fifo is no full */
#define SPI_PL022_SR_TFE (0x1 << 0) /* Whether to send fifo is empty */
#define REG_SPI_PL022_CPSR 0x10
#define SPI_PL022_CPSR_CPSDVSR_SHIFT 0
#define SPI_PL022_CPSR_CPSDVSR (0xff << 0) /* even 2~254 */
#define REG_SPI_PL022_IMSC 0x14
#define REG_SPI_PL022_RIS 0x18
#define REG_SPI_PL022_MIS 0x1c
#define REG_SPI_PL022_ICR 0x20
#define REG_SPI_CRG 0x120100e4 /* CRG_REG_BASE(0x12010000) + 0x0e4 */
#define SPI_CRG_CLK_EN 0
#define SPI_CRG_CLK_RST 0
#define REG_SPI_MISC_CTRL 0x12030024 /* MISC_REG_BASE(0x12030000) + 0x24 */
#define SPI_MISC_CTRL_CS 0
#define SPI_MISC_CTRL_CS_SHIFT 0
/* ********** spi reg offset define end *************** */
#define MAX_WAIT 5000
#define DEFAULT_SPEED 2000000
#define SCR_MAX 255
#define SCR_MIN 0
#define CPSDVSR_MAX 254
#define CPSDVSR_MIN 2
#define SPI_CS_ACTIVE 0
#define SPI_CS_INACTIVE 1
#define TWO_BYTES 2
#define BITS_PER_WORD_MIN 4
#define BITS_PER_WORD_DEFAULT 8
#define BITS_PER_WORD_MAX 16
struct Pl022SpiCntlr {
struct SpiCntlr *cntlr;
struct DListHead deviceList;
volatile unsigned char *regBase;
uint32_t busNum;
uint32_t numCs;
uint32_t curCs;
uint32_t speed;
uint32_t fifoSize;
uint32_t clkRate;
uint32_t maxSpeedHz;
uint32_t minSpeedHz;
uint32_t regCrg;
uint32_t clkEnBit;
uint32_t clkRstBit;
uint32_t regMiscCtrl;
uint32_t miscCtrlCsShift;
uint32_t miscCtrlCs;
uint16_t mode;
uint8_t bitsPerWord;
uint8_t transferMode;
};
int ConfigPl022SpiCntlr(struct Pl022SpiCntlr *cntlr);
int32_t TransferOneMessage(struct Pl022SpiCntlr *cntlr, struct SpiMsg *msg);
#endif // SPI_PL022_SAMPLE_H
+18
View File
@@ -0,0 +1,18 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef SPI_SAMPLE_H
#define SPI_SAMPLE_H
#include "spi_core.h"
int32_t SampleSpiCntlrTransfer(struct SpiCntlr *cntlr, struct SpiMsg *msg, uint32_t count);
int32_t SampleSpiCntlrSetCfg(struct SpiCntlr *cntlr, struct SpiCfg *cfg);
int32_t SampleSpiCntlrGetCfg(struct SpiCntlr *cntlr, struct SpiCfg *cfg);
#endif // SPI_SAMPLE_H
+23
View File
@@ -0,0 +1,23 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
#
# HDF is dual licensed: you can use it either under the terms of
# the GPL, or the BSD license, at your option.
# See the LICENSE file in the root of this repository for complete details.
import("//drivers/adapter/khdf/liteos/hdf.gni")
module_switch = defined(LOSCFG_DRIVERS_HDF_PLATFORM_SPI_SAMPLE)
module_name = "hdf_spi_sample"
hdf_driver(module_name) {
FRAMEWORK_SPI_ROOT = "//drivers/framework/sample/platform/spi/src"
sources = [
"$FRAMEWORK_SPI_ROOT/spi_dispatch_sample.c",
"$FRAMEWORK_SPI_ROOT/spi_pl022_sample.c",
"$FRAMEWORK_SPI_ROOT/spi_sample.c",
]
include_dirs = [
"//drivers/framework/sample/platform/spi/include/",
"//drivers/framework/support/platform/include/spi",
]
}
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "spi_dispatch_sample.h"
#include "spi_sample.h"
#include "hdf_log.h"
#include "hdf_sbuf.h"
#define HDF_LOG_TAG spi_dispatch_sample
static int32_t SampleSpiTransfer(struct SpiCntlr *cntlr, struct HdfSBuf *txBuf)
{
HDF_LOGD("%s: Enter", __func__);
uint32_t readSize = sizeof(struct SpiMsg);
struct SpiMsg *msg = NULL;
if (cntlr == NULL || cntlr->priv == NULL || txBuf == NULL) {
HDF_LOGE("%s: invalid parameter", __func__);
return HDF_ERR_INVALID_PARAM;
}
if (!HdfSbufReadBuffer(txBuf, (const void **)&msg, &readSize)) {
HDF_LOGE("%s: Failed to read sbuf", __func__);
return HDF_DEV_ERR_NO_MEMORY;
}
if (SampleSpiCntlrTransfer(cntlr, msg, msg->len) != HDF_SUCCESS) {
HDF_LOGE("%s: SampleSpiCntlrTransfer error", __func__);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
int32_t SampleSpiDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply)
{
if (client == NULL || client->device == NULL) {
HDF_LOGE("%s: client or client->device is NULL", __func__);
return HDF_FAILURE;
}
struct SpiCntlr *cntlr = (struct SpiCntlr *)client->device->service;
if (cntlr == NULL || cntlr->method == NULL) {
HDF_LOGE("%s: cntlr or cntlr->method is NULL", __func__);
return HDF_FAILURE;
}
switch (cmdId) {
case SPI_TRANSFER:
return SampleSpiTransfer(cntlr, data);
default:
HDF_LOGE("%s: invalid cmdId %d", __func__, cmdId);
return HDF_FAILURE;
}
}
+338
View File
@@ -0,0 +1,338 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "spi_pl022_sample.h"
#include "osal_io.h"
#define HDF_LOG_TAG spi_pl022_sample
/* Private function prototypes */
static int Pl022SampleSetCs(struct Pl022SpiCntlr *cntlr, uint32_t cs, uint32_t flag);
static int Pl022SampleFlushFifo(const struct Pl022SpiCntlr *cntlr);
static int Pl022SampleTxRx8(const struct Pl022SpiCntlr *cntlr, const struct SpiMsg *msg);
static int Pl022SampleTxRx16(const struct Pl022SpiCntlr *cntlr, const struct SpiMsg *msg);
static void Pl022SampleEnableCntlr(const struct Pl022SpiCntlr *cntlr);
static void Pl022SampleConfigCPSR(const struct Pl022SpiCntlr *cntlr, uint32_t cpsdvsr);
static void Pl022SampleConfigCR0(const struct Pl022SpiCntlr *cntlr, uint32_t scr);
static void Pl022SampleConfigCR1(const struct Pl022SpiCntlr *cntlr);
static int32_t Pl022SampleCfgCs(struct Pl022SpiCntlr *cntlr, uint32_t cs);
static void Pl022SampleDisableCntlr(const struct Pl022SpiCntlr *cntlr);
static int Pl022SampleCheckTimeout(const struct Pl022SpiCntlr *cntlr);
int ConfigPl022SpiCntlr(struct Pl022SpiCntlr *cntlr)
{
uint32_t tmp;
uint32_t scr;
uint32_t cpsdvsr;
Pl022SampleEnableCntlr(cntlr);
/* Check if we can provide the requested rate */
if (cntlr->speed > cntlr->maxSpeedHz) {
cntlr->speed = cntlr->maxSpeedHz;
}
/* Min possible */
if ((cntlr->speed < cntlr->minSpeedHz) || (cntlr->speed == 0)) {
HDF_LOGE("%s: cntlr->speed is %u not support, max %u, min %u", __func__,
cntlr->speed, cntlr->maxSpeedHz, cntlr->minSpeedHz);
return HDF_FAILURE;
}
/* Check if we can provide the requested bits_per_word */
if ((cntlr->bitsPerWord < BITS_PER_WORD_MIN) || (cntlr->bitsPerWord > BITS_PER_WORD_MAX)) {
HDF_LOGE("%s: cntlr->bitsPerWord is %u not support", __func__, cntlr->bitsPerWord);
return HDF_FAILURE;
}
/* compute spi speed, speed=clk/(cpsdvsr*(scr+1)) */
tmp = (cntlr->clkRate) / (cntlr->speed);
if (tmp < CPSDVSR_MIN) {
cpsdvsr = CPSDVSR_MIN;
scr = 0;
} else if (tmp <= CPSDVSR_MAX) {
cpsdvsr = tmp & (~0x1);
scr = (tmp / cpsdvsr) - 1;
} else {
cpsdvsr = CPSDVSR_MAX;
scr = (tmp / cpsdvsr) - 1;
}
/* config SPICPSR register */
Pl022SampleConfigCPSR(cntlr, cpsdvsr);
/* config SPICR0 register */
Pl022SampleConfigCR0(cntlr, scr);
/* config SPICR1 register */
Pl022SampleConfigCR1(cntlr);
return HDF_SUCCESS;
}
int32_t TransferOneMessage(struct Pl022SpiCntlr *cntlr, struct SpiMsg *msg)
{
int32_t ret;
if (msg->speed != 0) {
cntlr->speed = msg->speed;
}
ret = ConfigPl022SpiCntlr(cntlr);
if (ret != HDF_SUCCESS) {
return ret;
}
ret = Pl022SampleSetCs(cntlr, cntlr->curCs, SPI_CS_ACTIVE);
if (ret != HDF_SUCCESS) {
return ret;
}
ret = Pl022SampleFlushFifo(cntlr);
if (ret != HDF_SUCCESS) {
return ret;
}
if (cntlr->bitsPerWord <= BITS_PER_WORD_DEFAULT) {
ret = Pl022SampleTxRx8(cntlr, msg);
} else {
ret = Pl022SampleTxRx16(cntlr, msg);
}
if (ret || msg->csChange) {
Pl022SampleSetCs(cntlr, cntlr->curCs, SPI_CS_INACTIVE);
}
return ret;
}
/* Private function implementations */
static int Pl022SampleSetCs(struct Pl022SpiCntlr *cntlr, uint32_t cs, uint32_t flag)
{
if (Pl022SampleCfgCs(cntlr, cs) != HDF_SUCCESS) {
return HDF_FAILURE;
}
if (flag == SPI_CS_ACTIVE) {
Pl022SampleEnableCntlr(cntlr);
} else {
Pl022SampleDisableCntlr(cntlr);
}
return HDF_SUCCESS;
}
static int Pl022SampleFlushFifo(const struct Pl022SpiCntlr *cntlr)
{
uint32_t value;
uint32_t ret;
uint32_t tmp = 0;
ret = Pl022SampleCheckTimeout(cntlr);
if (ret != HDF_SUCCESS) {
return ret;
}
while (true) {
value = OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_SR);
if (!(value & SPI_PL022_SR_RNE)) {
break;
}
if (tmp++ > cntlr->fifoSize) {
HDF_LOGE("%s: spi transfer check rx fifo wait timeout", __func__);
return HDF_ERR_TIMEOUT;
}
OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_DR);
}
return HDF_SUCCESS;
}
static int Pl022SampleTxRx8(const struct Pl022SpiCntlr *cntlr, const struct SpiMsg *msg)
{
uint32_t len = msg->len;
uint32_t tmpLen;
uint32_t count;
const uint8_t *tx = (const uint8_t *)(msg->wbuf);
uint8_t *rx = (uint8_t *)(msg->rbuf);
uint8_t value;
uint32_t ret;
if (tx == NULL && rx == NULL) {
return HDF_ERR_INVALID_PARAM;
}
while (len > 0) {
if (len > cntlr->fifoSize) {
tmpLen = cntlr->fifoSize;
} else {
tmpLen = len;
}
len -= tmpLen;
/* write fifo */
count = tmpLen;
value = 0;
while (count > 0) {
if (tx != NULL) {
value = *tx++;
}
OSAL_WRITEL(value, (UINTPTR)(cntlr->regBase) + REG_SPI_PL022_DR);
count -= 1;
OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_SR);
}
ret = Pl022SampleCheckTimeout(cntlr);
if (ret != HDF_SUCCESS) {
return ret;
}
/* read fifo */
count = tmpLen;
while (count > 0) {
value = OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_DR);
if (rx != NULL) {
*rx++ = value;
}
count -= 1;
OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_SR);
}
}
return HDF_SUCCESS;
}
static int Pl022SampleTxRx16(const struct Pl022SpiCntlr *cntlr, const struct SpiMsg *msg)
{
uint32_t len = msg->len;
uint32_t tmpLen;
uint32_t count;
const uint16_t *tx = (const uint16_t *)(msg->wbuf);
uint16_t *rx = (uint16_t *)(msg->rbuf);
uint16_t value;
uint32_t ret;
if (tx == NULL && rx == NULL) {
return HDF_ERR_INVALID_PARAM;
}
while (len > 0) {
ret = cntlr->fifoSize * TWO_BYTES;
if (len > ret) {
tmpLen = ret;
} else {
tmpLen = len;
}
len -= tmpLen;
/* write fifo */
count = tmpLen;
value = 0;
while (count >= TWO_BYTES) {
if (tx != NULL) {
value = *tx++;
}
OSAL_WRITEL(value, (UINTPTR)(cntlr->regBase) + REG_SPI_PL022_DR);
count -= TWO_BYTES;
}
ret = Pl022SampleCheckTimeout(cntlr);
if (ret != 0) {
return ret;
}
/* read fifo */
count = tmpLen;
while (count >= TWO_BYTES) {
value = OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_DR);
if (rx != NULL) {
*rx++ = value;
}
count -= TWO_BYTES;
}
}
return 0;
}
static void Pl022SampleEnableCntlr(const struct Pl022SpiCntlr *cntlr)
{
uint32_t value;
value = OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_CR1);
value |= SPI_PL022_CR1_SSE;
OSAL_WRITEL(value, (UINTPTR)(cntlr->regBase) + REG_SPI_PL022_CR1);
}
static void Pl022SampleConfigCPSR(const struct Pl022SpiCntlr *cntlr, uint32_t cpsdvsr)
{
uint32_t value;
value = OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_CPSR);
value &= ~SPI_PL022_CPSR_CPSDVSR;
value |= cpsdvsr << SPI_PL022_CPSR_CPSDVSR_SHIFT;
OSAL_WRITEL(value, (UINTPTR)(cntlr->regBase) + REG_SPI_PL022_CPSR);
}
static void Pl022SampleConfigCR0(const struct Pl022SpiCntlr *cntlr, uint32_t scr)
{
uint32_t tmp;
uint32_t value;
value = OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_CR0);
value &= ~SPI_PL022_CR0_DSS;
value |= (cntlr->bitsPerWord - 1) << SPI_PL022_CR0_DSS_SHIFT;
value &= ~SPI_PL022_CR0_FRF;
value &= ~SPI_PL022_CR0_SPO;
tmp = (!!(cntlr->mode & SPI_CLK_POLARITY)) ? (1 << SPI_PL022_CR0_SPO_SHIFT) : 0;
value |= tmp;
value &= ~SPI_PL022_CR0_SPH;
tmp = (!!(cntlr->mode & SPI_CLK_PHASE)) ? (1 << SPI_PL022_CR0_SPH_SHIFT) : 0;
value |= tmp;
value &= ~SPI_PL022_CR0_SCR;
value |= (scr << SPI_PL022_CR0_SCR_SHIFT);
OSAL_WRITEL(value, (UINTPTR)(cntlr->regBase) + REG_SPI_PL022_CR0);
}
static void Pl022SampleConfigCR1(const struct Pl022SpiCntlr *cntlr)
{
uint32_t tmp;
uint32_t value;
value = OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_CR1);
value &= ~SPI_PL022_CR1_LBM;
tmp = (!!(cntlr->mode & SPI_MODE_LOOP)) ? (1 << SPI_PL022_CR1_LBN_SHIFT) : 0;
value |= tmp;
value &= ~SPI_PL022_CR1_MS;
value &= ~SPI_PL022_CR1_BIG_END;
tmp = (!!(cntlr->mode & SPI_MODE_LSBFE)) ? (1 << SPI_PL022_CR1_BIG_END_SHIFT) : 0;
value |= tmp;
value &= ~SPI_PL022_CR1_ALT;
value |= 0x1 << SPI_PL022_CR1_ALT_SHIFT;
OSAL_WRITEL(value, (UINTPTR)(cntlr->regBase) + REG_SPI_PL022_CR1);
}
static int32_t Pl022SampleCfgCs(struct Pl022SpiCntlr *cntlr, uint32_t cs)
{
uint32_t value;
uint32_t miscCtrlCs;
if ((cs + 1) > cntlr->numCs) {
HDF_LOGE("%s: cs %u is big than cntlr csNum %u", __func__, cs, cntlr->numCs);
return HDF_FAILURE;
}
if (cntlr->numCs == 1) {
return HDF_SUCCESS;
}
miscCtrlCs = (UINTPTR)(cntlr->regBase) + REG_SPI_MISC_CTRL;
value = OSAL_READL(miscCtrlCs);
value &= ~miscCtrlCs;
value |= (cs << cntlr->miscCtrlCsShift);
OSAL_WRITEL(value, miscCtrlCs);
return HDF_SUCCESS;
}
static void Pl022SampleDisableCntlr(const struct Pl022SpiCntlr *cntlr)
{
uint32_t value;
value = OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_CR1);
value &= ~SPI_PL022_CR1_SSE;
OSAL_WRITEL(value, (UINTPTR)(cntlr->regBase) + REG_SPI_PL022_CR1);
}
static int Pl022SampleCheckTimeout(const struct Pl022SpiCntlr *cntlr)
{
uint32_t value;
uint32_t tmp = 0;
while (true) {
value = OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_SR);
if ((value & SPI_PL022_SR_TFE) && (!(value & SPI_PL022_SR_BSY))) {
break;
}
if (tmp++ > MAX_WAIT) {
HDF_LOGE("%s: spi transfer wait timeout", __func__);
return HDF_ERR_TIMEOUT;
}
OsalUDelay(1);
}
return HDF_SUCCESS;
}
+355
View File
@@ -0,0 +1,355 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "spi_sample.h"
#include "spi_pl022_sample.h"
#include "spi_dispatch_sample.h"
#include "device_resource_if.h"
#include "hdf_base.h"
#include "osal_mem.h"
#include "hdf_log.h"
#include "spi_core.h"
#include "los_vm_zone.h"
#define HDF_LOG_TAG spi_sample
/* HdfDriverEntry hook function prototypes */
static int32_t SampleSpiDriverBind(struct HdfDeviceObject *device);
static int32_t SampleSpiDriverInit(struct HdfDeviceObject *device);
static void SampleSpiDriverRelease(struct HdfDeviceObject *device);
/* SpiCntlrMethod definition */
struct SpiCntlrMethod g_sampleSpiMethod = {
.Transfer = SampleSpiCntlrTransfer,
.SetCfg = SampleSpiCntlrSetCfg,
.GetCfg = SampleSpiCntlrGetCfg,
};
/* HdfDriverEntry definition */
struct HdfDriverEntry g_sampleSpiDriverEntry = {
.moduleVersion = 1,
.moduleName = "SPI_SAMPLE",
.Bind = SampleSpiDriverBind,
.Init = SampleSpiDriverInit,
.Release = SampleSpiDriverRelease,
};
/* Init HdfDriverEntry */
HDF_INIT(g_sampleSpiDriverEntry);
/* Private function prototypes */
static int InitSpiDevice(struct SpiCntlr *cntlr, const struct DeviceResourceNode *property);
static int ConfigSpiDevice(struct Pl022SpiCntlr *pl022Cntlr);
static int32_t InitSpiDeviceResource(struct Pl022SpiCntlr *pl022Cntlr, const struct DeviceResourceNode *node);
static int32_t CreateSpiDev(struct Pl022SpiCntlr *pl022Cntlr);
static void ReleaseSpiDev(struct Pl022SpiCntlr *pl022Cntlr);
static struct SpiDev *FindDeviceByCsNum(const struct Pl022SpiCntlr *pl022Cntlr, uint32_t cs);
/* HdfDriverEntry hook function implementations */
static int32_t SampleSpiDriverBind(struct HdfDeviceObject *device)
{
HDF_LOGD("%s: Enter", __func__);
struct SpiCntlr *cntlr = NULL;
if (device == NULL) {
HDF_LOGE("%s: device is NULL", __func__);
return HDF_ERR_INVALID_OBJECT;
}
cntlr = SpiCntlrCreate(device);
if (cntlr == NULL) {
HDF_LOGE("%s: cntlr is NULL", __func__);
return HDF_FAILURE;
}
cntlr->service.Dispatch = SampleSpiDispatch;
return HDF_SUCCESS;
}
static int32_t SampleSpiDriverInit(struct HdfDeviceObject *device)
{
HDF_LOGD("%s: Enter", __func__);
int ret;
struct SpiCntlr *cntlr = NULL;
if (device == NULL || device->property == NULL) {
HDF_LOGE("%s: device or device->property is null", __func__);
return HDF_ERR_INVALID_OBJECT;
}
cntlr = SpiCntlrFromDevice(device);
if (cntlr == NULL) {
HDF_LOGE("%s: cntlr is null", __func__);
return HDF_ERR_INVALID_OBJECT;
}
ret = InitSpiDevice(cntlr, device->property);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: InitSpiDevice failed", __func__);
return ret;
}
ret = ConfigSpiDevice(cntlr->priv);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: ConfigSpiDevice failed", __func__);
return ret;
}
return ret;
}
static void SampleSpiDriverRelease(struct HdfDeviceObject *device)
{
HDF_LOGD("%s: Enter", __func__);
struct SpiCntlr *cntlr = NULL;
if (device == NULL) {
HDF_LOGE("%s: device is null", __func__);
return;
}
cntlr = SpiCntlrFromDevice(device);
if (cntlr == NULL) {
HDF_LOGE("%s: cntlr is null", __func__);
return;
}
if (cntlr->priv != NULL) {
ReleaseSpiDev((struct Pl022SpiCntlr *)cntlr->priv);
}
SpiCntlrDestroy(cntlr);
}
/* SPI function implementations */
int32_t SampleSpiCntlrTransfer(struct SpiCntlr *cntlr, struct SpiMsg *msg, uint32_t count)
{
HDF_LOGD("%s: Enter", __func__);
int ret;
struct Pl022SpiCntlr *pl022Cntlr = NULL;
struct SpiDev *spiDev = NULL;
if (cntlr == NULL || cntlr->priv == NULL || msg == NULL || count == 0) {
HDF_LOGE("%s: invalid parameter", __func__);
return HDF_ERR_INVALID_PARAM;
}
pl022Cntlr = (struct Pl022SpiCntlr *)cntlr->priv;
spiDev = FindDeviceByCsNum(pl022Cntlr, cntlr->curCs);
if (spiDev == NULL) {
HDF_LOGE("%s: spiDev is null, curCs %u", __func__, cntlr->curCs);
return HDF_FAILURE;
}
pl022Cntlr->mode = spiDev->cfg.mode;
pl022Cntlr->transferMode = spiDev->cfg.transferMode;
pl022Cntlr->bitsPerWord = spiDev->cfg.bitsPerWord;
pl022Cntlr->maxSpeedHz = spiDev->cfg.maxSpeedHz;
pl022Cntlr->curCs = spiDev->csNum;
for (uint32_t i = 0; i < count; i++) {
ret = TransferOneMessage(pl022Cntlr, &(msg[i]));
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: transfer error", __func__);
return ret;
}
}
return ret;
}
int32_t SampleSpiCntlrSetCfg(struct SpiCntlr *cntlr, struct SpiCfg *cfg)
{
HDF_LOGD("%s: Enter", __func__);
struct Pl022SpiCntlr *pl022Cntlr = NULL;
struct SpiDev *spiDev = NULL;
if (cntlr == NULL || cntlr->priv == NULL || cfg == NULL) {
HDF_LOGE("%s: invalid parameter", __func__);
return HDF_ERR_INVALID_PARAM;
}
pl022Cntlr = (struct Pl022SpiCntlr *)cntlr->priv;
spiDev = FindDeviceByCsNum(pl022Cntlr, cntlr->curCs);
if (spiDev == NULL) {
HDF_LOGE("%s: spiDev is null, curCs %u", __func__, cntlr->curCs);
return HDF_FAILURE;
}
spiDev->cfg.mode = cfg->mode;
spiDev->cfg.transferMode = cfg->transferMode;
spiDev->cfg.bitsPerWord = cfg->bitsPerWord;
if ((cfg->bitsPerWord < BITS_PER_WORD_MIN) || (cfg->bitsPerWord > BITS_PER_WORD_MAX)) {
HDF_LOGE("%s: bitsPerWord %u not support, use default bitsPerWord %u",
__func__, cfg->bitsPerWord, BITS_PER_WORD_DEFAULT);
spiDev->cfg.bitsPerWord = BITS_PER_WORD_DEFAULT;
}
if (cfg->maxSpeedHz != 0) {
spiDev->cfg.maxSpeedHz = cfg->maxSpeedHz;
}
return HDF_SUCCESS;
}
int32_t SampleSpiCntlrGetCfg(struct SpiCntlr *cntlr, struct SpiCfg *cfg)
{
HDF_LOGD("%s: Enter", __func__);
struct Pl022SpiCntlr *pl022Cntlr = NULL;
struct SpiDev *spiDev = NULL;
if (cntlr == NULL || cntlr->priv == NULL || cfg == NULL) {
HDF_LOGE("%s: invalid parameter", __func__);
return HDF_ERR_INVALID_PARAM;
}
pl022Cntlr = (struct Pl022SpiCntlr *)cntlr->priv;
spiDev = FindDeviceByCsNum(pl022Cntlr, cntlr->curCs);
if (spiDev == NULL) {
HDF_LOGE("%s: spiDev is null, curCs %u", __func__, cntlr->curCs);
return HDF_FAILURE;
}
cfg->mode = spiDev->cfg.mode;
cfg->transferMode = spiDev->cfg.transferMode;
cfg->bitsPerWord = spiDev->cfg.bitsPerWord;
cfg->maxSpeedHz = spiDev->cfg.maxSpeedHz;
return HDF_SUCCESS;
}
/* Private function implementations */
static int InitSpiDevice(struct SpiCntlr *cntlr, const struct DeviceResourceNode *property)
{
int ret;
struct Pl022SpiCntlr *pl022Cntlr = NULL;
pl022Cntlr = (struct Pl022SpiCntlr *)OsalMemCalloc(sizeof(*pl022Cntlr));
if (pl022Cntlr == NULL) {
HDF_LOGE("%s: OsalMemCalloc error", __func__);
return HDF_FAILURE;
}
ret = InitSpiDeviceResource(pl022Cntlr, property);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: InitSpiDeviceResource error", __func__);
OsalMemFree(pl022Cntlr);
return HDF_FAILURE;
}
pl022Cntlr->maxSpeedHz = (pl022Cntlr->clkRate) / ((SCR_MIN + 1) * CPSDVSR_MIN);
pl022Cntlr->minSpeedHz = (pl022Cntlr->clkRate) / ((SCR_MAX + 1) * CPSDVSR_MAX);
DListHeadInit(&pl022Cntlr->deviceList);
pl022Cntlr->cntlr = cntlr;
cntlr->priv = pl022Cntlr;
cntlr->busNum = pl022Cntlr->busNum;
cntlr->method = &g_sampleSpiMethod;
ret = CreateSpiDev(pl022Cntlr);
if (ret != HDF_SUCCESS) {
ReleaseSpiDev(pl022Cntlr);
return ret;
}
return HDF_SUCCESS;
}
static int ConfigSpiDevice(struct Pl022SpiCntlr *pl022Cntlr)
{
int ret;
ret = ConfigPl022SpiCntlr(pl022Cntlr);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: HiPl022Config error", __func__);
}
return ret;
}
static int32_t InitSpiDeviceResource(struct Pl022SpiCntlr *pl022Cntlr, const struct DeviceResourceNode *node)
{
uint32_t tmp;
struct DeviceResourceIface *resIf = NULL;
resIf = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
if (resIf == NULL || resIf->GetUint8 == NULL || resIf->GetUint16 == NULL || resIf->GetUint32 == NULL) {
HDF_LOGE("%s: resource is invalid", __func__);
return HDF_FAILURE;
}
if (resIf->GetUint32(node, "regBase", &tmp, 0) != HDF_SUCCESS) {
HDF_LOGE("%s: read regBase fail", __func__);
return HDF_FAILURE;
}
pl022Cntlr->regBase = (void *)(uintptr_t)(IO_DEVICE_ADDR(tmp));
if (resIf->GetUint32(node, "busNum", &pl022Cntlr->busNum, 0) != HDF_SUCCESS) {
HDF_LOGE("%s: read busNum fail", __func__);
return HDF_FAILURE;
}
if (resIf->GetUint32(node, "numCs", &pl022Cntlr->numCs, 0) != HDF_SUCCESS) {
HDF_LOGE("%s: read numCs fail", __func__);
return HDF_FAILURE;
}
if (resIf->GetUint32(node, "speed", &pl022Cntlr->speed, DEFAULT_SPEED) != HDF_SUCCESS) {
HDF_LOGE("%s: read speed fail", __func__);
return HDF_FAILURE;
}
if (resIf->GetUint32(node, "fifoSize", &pl022Cntlr->fifoSize, 0) != HDF_SUCCESS) {
HDF_LOGE("%s: read fifoSize fail", __func__);
return HDF_FAILURE;
}
if (resIf->GetUint32(node, "clkRate", &pl022Cntlr->clkRate, 0) != HDF_SUCCESS) {
HDF_LOGE("%s: read clkRate fail", __func__);
return HDF_FAILURE;
}
if (resIf->GetUint16(node, "mode", &pl022Cntlr->mode, 0) != HDF_SUCCESS) {
HDF_LOGE("%s: read mode fail", __func__);
return HDF_FAILURE;
}
if (resIf->GetUint8(node, "bitsPerWord", &pl022Cntlr->bitsPerWord, 0) != HDF_SUCCESS) {
HDF_LOGE("%s: read bitsPerWord fail", __func__);
return HDF_FAILURE;
}
if (resIf->GetUint8(node, "transferMode", &pl022Cntlr->transferMode, 0) != HDF_SUCCESS) {
HDF_LOGE("%s: read comMode fail", __func__);
return HDF_FAILURE;
}
pl022Cntlr->regCrg = REG_SPI_CRG;
pl022Cntlr->clkEnBit = SPI_CRG_CLK_EN;
pl022Cntlr->clkRstBit = SPI_CRG_CLK_RST;
pl022Cntlr->regMiscCtrl = REG_SPI_MISC_CTRL;
pl022Cntlr->miscCtrlCs = SPI_MISC_CTRL_CS;
pl022Cntlr->miscCtrlCsShift = SPI_MISC_CTRL_CS_SHIFT;
return HDF_SUCCESS;
}
static int32_t CreateSpiDev(struct Pl022SpiCntlr *pl022Cntlr)
{
uint32_t i;
struct SpiDev *device = NULL;
for (i = 0; i < pl022Cntlr->numCs; i++) {
device = (struct SpiDev *)OsalMemCalloc(sizeof(*device));
if (device == NULL) {
HDF_LOGE("%s: OsalMemCalloc error", __func__);
return HDF_FAILURE;
}
device->cntlr = pl022Cntlr->cntlr;
device->csNum = i;
device->cfg.bitsPerWord = pl022Cntlr->bitsPerWord;
device->cfg.transferMode = pl022Cntlr->transferMode;
device->cfg.maxSpeedHz = pl022Cntlr->maxSpeedHz;
device->cfg.mode = pl022Cntlr->mode;
DListHeadInit(&device->list);
DListInsertTail(&device->list, &pl022Cntlr->deviceList);
}
return HDF_SUCCESS;
}
static void ReleaseSpiDev(struct Pl022SpiCntlr *pl022Cntlr)
{
struct SpiDev *dev = NULL;
struct SpiDev *tmpDev = NULL;
DLIST_FOR_EACH_ENTRY_SAFE(dev, tmpDev, &(pl022Cntlr->deviceList), struct SpiDev, list) {
if (dev != NULL) {
DListRemove(&(dev->list));
OsalMemFree(dev);
}
}
OsalMemFree(pl022Cntlr);
}
static struct SpiDev *FindDeviceByCsNum(const struct Pl022SpiCntlr *pl022Cntlr, uint32_t cs)
{
struct SpiDev *dev = NULL;
struct SpiDev *tmpDev = NULL;
if (pl022Cntlr == NULL || pl022Cntlr->numCs <= cs) {
return NULL;
}
DLIST_FOR_EACH_ENTRY_SAFE(dev, tmpDev, &(pl022Cntlr->deviceList), struct SpiDev, list) {
if (dev->csNum == cs) {
break;
}
}
return dev;
}
+14
View File
@@ -0,0 +1,14 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
#
# HDF is dual licensed: you can use it either under the terms of
# the GPL, or the BSD license, at your option.
# See the LICENSE file in the root of this repository for complete details.
import("//build/lite/config/component/lite_component.gni")
lite_component("hello_uart_sample") {
features = [
"dev:hello_uart",
"dispatch:hello_uart_dispatch",
]
}
+12
View File
@@ -0,0 +1,12 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
#
# HDF is dual licensed: you can use it either under the terms of
# the GPL, or the BSD license, at your option.
# See the LICENSE file in the root of this repository for complete details.
config DRIVERS_HDF_PLATFORM_UART_SAMPLE
bool "Enable HDF platform uart sample driver"
default n
depends on DRIVERS_HDF_PLATFORM
help
Answer Y to enable HDF platform uart sample driver.
+41
View File
@@ -0,0 +1,41 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
#
# HDF is dual licensed: you can use it either under the terms of
# the GPL, or the BSD license, at your option.
# See the LICENSE file in the root of this repository for complete details.
HDF_FRAMEWORKS = "//drivers/framework"
executable("hello_uart") {
sources = [ "hello_uart_dev.c" ]
include_dirs = [
"$HDF_FRAMEWORKS/ability/sbuf/include",
"$HDF_FRAMEWORKS/core/shared/include",
"$HDF_FRAMEWORKS/core/host/include",
"$HDF_FRAMEWORKS/core/master/include",
"$HDF_FRAMEWORKS/include/core",
"$HDF_FRAMEWORKS/include/utils",
"$HDF_FRAMEWORKS/utils/include",
"$HDF_FRAMEWORKS/include/osal",
"//drivers/adapter/uhdf/posix/include",
"//third_party/bounds_checking_function/include",
"//base/hiviewdfx/hilog_lite/interfaces/native/innerkits",
]
deps = [
"//base/hiviewdfx/hilog_lite/frameworks/featured:hilog_shared",
"//drivers/adapter/uhdf/manager:hdf_core",
"//drivers/adapter/uhdf/posix:hdf_posix_osal",
]
public_deps = [ "//third_party/bounds_checking_function:libsec_shared" ]
defines = [ "__USER__" ]
cflags = [
"-Wall",
"-Wextra",
"-Wno-format",
"-Wno-format-extra-args",
]
}
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include "hdf_log.h"
#define HDF_LOG_TAG hello_uart
#define INFO_SIZE 16
int main(void)
{
int ret;
int fd;
const char info[INFO_SIZE] = {" HELLO UART! "};
fd = open("/dev/uartdev-5", O_RDWR);
if (fd < 0) {
HDF_LOGE("uartdev-5 open failed %d", fd);
return -1;
}
ret = write(fd, info, INFO_SIZE);
if (ret != 0) {
HDF_LOGE("write uartdev-5 ret is %d", ret);
}
ret = close(fd);
if (ret != 0) {
HDF_LOGE("uartdev-5 close failed %d", fd);
return -1;
}
return ret;
}
+44
View File
@@ -0,0 +1,44 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
#
# HDF is dual licensed: you can use it either under the terms of
# the GPL, or the BSD license, at your option.
# See the LICENSE file in the root of this repository for complete details.
HDF_FRAMEWORKS = "//drivers/framework"
executable("hello_uart_dispatch") {
sources = [
"hello_uart_dispatch.c",
"uart_if.c",
]
include_dirs = [
"$HDF_FRAMEWORKS/ability/sbuf/include",
"$HDF_FRAMEWORKS/core/shared/include",
"$HDF_FRAMEWORKS/core/host/include",
"$HDF_FRAMEWORKS/core/master/include",
"$HDF_FRAMEWORKS/include/core",
"$HDF_FRAMEWORKS/include/utils",
"$HDF_FRAMEWORKS/utils/include",
"$HDF_FRAMEWORKS/include/osal",
"//drivers/adapter/uhdf/posix/include",
"//third_party/bounds_checking_function/include",
"//base/hiviewdfx/hilog_lite/interfaces/native/innerkits",
]
deps = [
"//base/hiviewdfx/hilog_lite/frameworks/featured:hilog_shared",
"//drivers/adapter/uhdf/manager:hdf_core",
"//drivers/adapter/uhdf/posix:hdf_posix_osal",
]
public_deps = [ "//third_party/bounds_checking_function:libsec_shared" ]
defines = [ "__USER__" ]
cflags = [
"-Wall",
"-Wextra",
"-Wno-format",
"-Wno-format-extra-args",
]
}
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include <string.h>
#include "hdf_log.h"
#include "osal_mem.h"
#include "uart_if.h"
#define HDF_LOG_TAG hello_uart_dispatch
#define UART_PORT 5
int main()
{
const char *info = " HELLO UART! ";
struct DevHandle *handle = UartOpen(UART_PORT);
if (handle == NULL) {
HDF_LOGE("Failed to open uart %d", UART_PORT);
return HDF_FAILURE;
}
int ret = UartWrite(handle, (uint8_t *)info, strlen(info));
if (ret != HDF_SUCCESS) {
HDF_LOGE("Failed to send data to uart");
}
UartClose(handle);
return ret;
}
+97
View File
@@ -0,0 +1,97 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "uart_if.h"
#include "securec.h"
#include "hdf_log.h"
#include "osal_mem.h"
#include "hdf_io_service_if.h"
#define HDF_LOG_TAG uart_if
struct DevHandle *UartOpen(uint32_t port)
{
int32_t ret;
struct DevHandle *handle = NULL;
char *serviceName = NULL;
handle = (struct DevHandle *)OsalMemCalloc(sizeof(struct DevHandle));
if (handle == NULL) {
HDF_LOGE("Failed to OsalMemCalloc handle");
return NULL;
}
serviceName = (char *)OsalMemCalloc(sizeof(char) * (MAX_DEV_NAME_SIZE + 1));
if (serviceName == NULL) {
HDF_LOGE("Failed to OsalMemCalloc serviceName");
OsalMemFree(handle);
return NULL;
}
ret = snprintf_s(serviceName, MAX_DEV_NAME_SIZE + 1, MAX_DEV_NAME_SIZE, UART_DEV_SERVICE_NAME_PREFIX, port);
if (ret < 0) {
HDF_LOGE("Failed to snprintf_s");
OsalMemFree(handle);
OsalMemFree(serviceName);
return NULL;
}
struct HdfIoService *service = HdfIoServiceBind(serviceName);
if (service == NULL) {
HDF_LOGE("Failed to get service %s", serviceName);
OsalMemFree(handle);
OsalMemFree(serviceName);
return NULL;
}
OsalMemFree(serviceName);
handle->object = service;
return handle;
}
int32_t UartWrite(struct DevHandle *handle, uint8_t *data, uint32_t size)
{
int ret;
struct HdfIoService *service = NULL;
if (handle == NULL || handle->object == NULL) {
HDF_LOGE("handle or handle->object is NULL");
return HDF_FAILURE;
}
struct HdfSBuf *sBuf = HdfSBufObtainDefaultSize();
if (sBuf == NULL) {
HDF_LOGE("Failed to obtain sBuf");
return HDF_FAILURE;
}
if (!HdfSbufWriteBuffer(sBuf, data, size)) {
HDF_LOGE("Failed to write sbuf");
HdfSBufRecycle(sBuf);
return HDF_FAILURE;
}
service = (struct HdfIoService *)handle->object;
ret = service->dispatcher->Dispatch(&service->object, UART_WRITE, sBuf, NULL);
if (ret != HDF_SUCCESS) {
HDF_LOGE("Failed to send service call");
}
HdfSBufRecycle(sBuf);
return ret;
}
void UartClose(struct DevHandle *handle)
{
struct HdfIoService *service = NULL;
if (handle == NULL || handle->object == NULL) {
HDF_LOGE("handle or handle->object is NULL");
return;
}
service = (struct HdfIoService *)handle->object;
HdfIoServiceRecycle(service);
OsalMemFree(handle);
}
+29
View File
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef UART_IF_H
#define UART_IF_H
#include <stdint.h>
#define UART_DEV_SERVICE_NAME_PREFIX "HDF_PLATFORM_UART_%d"
#define MAX_DEV_NAME_SIZE 32
enum {
UART_WRITE = 1
};
struct DevHandle {
void *object;
};
struct DevHandle *UartOpen(uint32_t port);
int32_t UartWrite(struct DevHandle *handle, uint8_t *data, uint32_t size);
void UartClose(struct DevHandle *handle);
#endif // UART_IF_H
+36
View File
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef BUF_FIFO_H
#define BUF_FIFO_H
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
struct BufferFifo {
volatile uint32_t readPosition;
volatile uint32_t writePosition;
uint16_t bufSizeMask;
uint8_t *buffer;
};
static inline uint16_t BufferFifoGetDataSize(struct BufferFifo *fifo)
{
return (fifo->writePosition - fifo->readPosition);
}
static inline bool IsPowerOfTwo(int num)
{
return (num > 0) && (num & (num - 1)) == 0;
}
bool BufferFifoInit(struct BufferFifo *fifo, uint8_t *buf, uint16_t bufSize);
#endif // BUF_FIFO_H
+35
View File
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef UART_DEV_SAMPLE_H
#define UART_DEV_SAMPLE_H
#include "sys/ioctl.h"
#include "uart_core.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#define UART_IOC_MAGIC 'u'
/* baudrate config */
#define UART_CFG_BAUDRATE _IO(UART_IOC_MAGIC, 1)
void AddUartDevice(struct UartHost *host);
void RemoveUartDevice(struct UartHost *host);
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */
#endif /* UART_DEV_SAMPLE_H */
+20
View File
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef UART_DISPATCH_SAMPLE_H
#define UART_DISPATCH_SAMPLE_H
#include "uart_pl011_sample.h"
enum {
UART_WRITE = 1
};
int32_t SampleDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply);
#endif // UART_DISPATCH_SAMPLE_H
+243
View File
@@ -0,0 +1,243 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef UART_PL011_SAMPLE_H
#define UART_PL011_SAMPLE_H
#include <stdint.h>
#include <stdbool.h>
#include "hdf_device_desc.h"
#include "buf_fifo.h"
#ifdef __cplusplus
extern "C" {
#endif
struct UartRegisterMap {
volatile uint32_t dr; /* Offset: 0x000 TYPE: (RW) Data register */
union {
volatile uint32_t rsr; /* Offset: 0x004 TYPE: (RO) Receive status register */
volatile uint32_t ecr; /* Offset: 0x004 TYPE: (WO) Error clear register */
};
volatile uint32_t reserved0[4]; /* Offset: 0x008-0x014 Reserved */
volatile uint32_t fr; /* Offset: 0x018 TYPE: (RO) Flag register */
volatile uint32_t reserved1; /* Offset: 0x01C Reserved */
volatile uint32_t ilpr; /* Offset: 0x020 TYPE: (RW) IrDA low-power counter register */
volatile uint32_t ibrd; /* Offset: 0x024 TYPE: (RW) Integer baud rate register */
volatile uint32_t fbrd; /* Offset: 0x028 TYPE: (RW) Fractional baud rate register */
volatile uint32_t lcr; /* Offset: 0x02C TYPE: (RW) Line control register */
volatile uint32_t cr; /* Offset: 0x030 TYPE: (RW) Control register */
volatile uint32_t ifls; /* Offset: 0x034 TYPE: (RW) Interrupt FIFO level select register */
volatile uint32_t imsc; /* Offset: 0x038 TYPE: (RW) Interrupt mask set/clear register */
volatile uint32_t ris; /* Offset: 0x03C TYPE: (RO) Raw interrupt status register */
volatile uint32_t mis; /* Offset: 0x040 TYPE: (RO) Masked interrupt status register */
volatile uint32_t icr; /* Offset: 0x044 TYPE: (WO) Interrupt clear register */
volatile uint32_t dmacr; /* Offset: 0x048 TYPE: (RW) DMA control register */
};
struct UartResource {
uint32_t num; /* UART port num */
uint32_t base; /* UART PL011 base address */
uint32_t irqNum; /* UART PL011 IRQ num */
uint32_t baudrate; /* Default baudrate */
uint32_t wlen; /* Default word length */
uint32_t parity; /* Default parity */
uint32_t stopBit; /* Default stop bits */
uint32_t uartClk; /* UART clock */
unsigned long physBase;
};
enum UartDeviceState {
UART_DEVICE_UNINITIALIZED = 0x0u,
UART_DEVICE_INITIALIZED = 0x1u,
};
struct UartDevice {
struct IDeviceIoService ioService;
struct UartResource resource;
enum UartDeviceState state; /* UART State */
uint32_t uartClk; /* UART clock */
uint32_t baudrate; /* Baudrate */
struct BufferFifo rxFifo;
};
/* Receive Status Register/Error Clear Register data */
#define UART_PL011_RSR_FRAMING_ERROR_MASK (1 << 0x0u) /* Framing error bit mask */
#define UART_PL011_RSR_PARITY_ERROR_MASK (1 << 0x1u) /* Parity error bit mask */
#define UART_PL011_RSR_BREAK_ERROR_MASK (1 << 0x2u) /* Break error bit mask */
#define UART_PL011_RSR_OVERRUN_ERROR_MASK (1 << 0x3u) /* Overrun error bit mask */
/* Receive Status Register Error Mask */
#define UART_PL011_RSR_RX_ERROR_MASK ( \
UART_PL011_RSR_FRAMING_ERROR_MASK \
| UART_PL011_RSR_PARITY_ERROR_MASK \
| UART_PL011_RSR_BREAK_ERROR_MASK \
| UART_PL011_RSR_OVERRUN_ERROR_MASK)
#define UART_PL011_FR_CTS_MASK (1 << 0x0u) /* Clear to send bit mask */
#define UART_PL011_FR_DSR_MASK (1 << 0x1u) /* Data set ready bit mask */
#define UART_PL011_FR_DCD_MASK (1 << 0x2u) /* Data carrier detect bit mask */
#define UART_PL011_FR_BUSY_MASK (1 << 0x3u) /* UART busy bit mask */
#define UART_PL011_FR_RX_FIFO_EMPTY_MASK (1 << 0x4u) /* Receive FIFO empty bit mask */
#define UART_PL011_FR_TX_FIFO_FULL_MASK (1 << 0x5u) /* Transmit FIFO full bit mask */
#define UART_PL011_FR_RX_FIFO_FULL_MASK (1 << 0x6u) /* Receive FIFO full bit mask */
#define UART_PL011_FR_TX_FIFO_EMPTY_MASK (1 << 0x7u) /* Transmit FIFO empty. bit mask */
#define UART_PL011_FR_RI_MASK (1 << 0x8u) /* Ring indicator bit mask */
/* PL011 Line Control Register Data bits */
#define UART_PL011_LCR_H_BRK_MASK (1 << 0x0u) /* Send Break bit mask */
#define UART_PL011_LCR_H_PEN_MASK (1 << 0x1u) /* Parity enable bit mask */
#define UART_PL011_LCR_H_EPS_MASK (1 << 0x2u) /* Even parity select bit mask . */
#define UART_PL011_LCR_H_FEN_MASK (1 << 0x4u) /* Enable FIFOs bit mask */
#define UART_PL011_LCR_H_SPS_MASK (1 << 0x7u) /* Stick parity select bit mask */
#define UART_PL011_LCR_H_WLEN_BIT_OFFSET 0x5u /* Word length bit offset */
#define UART_PL011_LCR_H_WLEN_MASK ( \
0x3u << UART_PL011_LCR_H_WLEN_BIT_OFFSET)
#define UART_PL011_WLEN_5BITS (0x0u << UART_PL011_LCR_H_WLEN_BIT_OFFSET)
#define UART_PL011_WLEN_6BITS (0x1u << UART_PL011_LCR_H_WLEN_BIT_OFFSET)
#define UART_PL011_WLEN_7BITS (0x2u << UART_PL011_LCR_H_WLEN_BIT_OFFSET)
#define UART_PL011_WLEN_8BITS (0x3u << UART_PL011_LCR_H_WLEN_BIT_OFFSET)
#define UART_PL011_NONE_PARITY_CHECKED 0
#define UART_PL011_LCR_H_STP2_BIT_OFFSET 0x3u /* Two stop bits select */
#define UART_PL011_STOPBIT_1 (0x0u << UART_PL011_LCR_H_STP2_BIT_OFFSET)
#define UART_PL011_STOPBIT_2 (0x1u << UART_PL011_LCR_H_STP2_BIT_OFFSET)
#define UART_PL011_LCR_H_PARITY_MASK ( \
UART_PL011_LCR_H_PEN_MASK \
| UART_PL011_LCR_H_EPS_MASK \
| UART_PL011_LCR_H_SPS_MASK)
#define UART_PL011_LCR_H_STOPBIT_MASK \
(0x1u << UART_PL011_LCR_H_STP2_BIT_OFFSET)
#define UART_PL011_DATA_FORMAT_MASK ( \
UART_PL011_LCR_H_PARITY_MASK \
| UART_PL011_LCR_H_STOPBIT_MASK \
| UART_PL011_LCR_H_WLEN_MASK)
/* Control Register */
#define UART_PL011_CR_UARTEN_MASK (0x1u << 0x0u) /* Uart enable bit mask */
#define UART_PL011_CR_SIREN_MASK (0x1u << 0x1u) /* Sir enable bit mask */
#define UART_PL011_CR_SIRLP_MASK (0x1u << 0x2u) /* SIR low-power IrDA mode bit mask */
#define UART_PL011_CR_LBE_MASK (0x1u << 0x7u) /* Loopback enable bit mask */
#define UART_PL011_CR_TXE_MASK (0x1u << 0x8u) /* Transmit enable bit mask */
#define UART_PL011_CR_RXE_MASK (0x1u << 0x9u) /* Receive enable bit mask */
#define UART_PL011_CR_DTR_MASK (0x1u << 0xAu) /* Data transmit ready.bit mask */
#define UART_PL011_CR_RTS_MASK (0x1u << 0xBu) /* Request to send bit mask */
#define UART_PL011_CR_OUT1_MASK (0x1u << 0xCu) /* Out1 bit field mask */
#define UART_PL011_CR_OUT2_MASK (0x1u << 0xDu) /* Out2 bit field mask */
#define UART_PL011_CR_RTSE_MASK (0x1u << 0xEu) /* RTS hardware flow control enable bit mask */
#define UART_PL011_CR_CTSE_MASK (0x1u << 0xFu) /* CTS hardware flow control enable bit mask */
/* Interrupt FIFO Level Select Register Transmit bit offset */
#define UART_PL011_IFLS_TX_BIT_OFFSET 0x0u
/* Interrupt FIFO Level Select Register Receive bit offset */
#define UART_PL011_IFLS_RX_BIT_OFFSET 0x3u
#define UART_PL011_RX_FIFO_LVL_1_8 (0x0u << UART_PL011_IFLS_RX_BIT_OFFSET)
#define UART_PL011_RX_FIFO_LVL_1_4 (0x1u << UART_PL011_IFLS_RX_BIT_OFFSET)
#define UART_PL011_RX_FIFO_LVL_1_2 (0x2u << UART_PL011_IFLS_RX_BIT_OFFSET)
#define UART_PL011_RX_FIFO_LVL_3_4 (0x3u << UART_PL011_IFLS_RX_BIT_OFFSET)
#define UART_PL011_RX_FIFO_LVL_7_8 (0x4u << UART_PL011_IFLS_RX_BIT_OFFSET)
#define UART_PL011_TX_FIFO_LVL_1_8 (0x0u << UART_PL011_IFLS_TX_BIT_OFFSET)
#define UART_PL011_TX_FIFO_LVL_1_4 (0x1u << UART_PL011_IFLS_TX_BIT_OFFSET)
#define UART_PL011_TX_FIFO_LVL_1_2 (0x2u << UART_PL011_IFLS_TX_BIT_OFFSET)
#define UART_PL011_TX_FIFO_LVL_3_4 (0x3u << UART_PL011_IFLS_TX_BIT_OFFSET)
#define UART_PL011_TX_FIFO_LVL_7_8 (0x4u << UART_PL011_IFLS_TX_BIT_OFFSET)
/* Default register values of UART PL011 */
#define UART_PL011_DEFAULT_DATA_REG_VALUE (0x0u)
#define UART_PL011_DEFAULT_ECR_VALUE (0xFFu)
#define UART_PL011_DEFAULT_ILPR_VALUE (0x0u)
#define UART_PL011_DEFAULT_IBRD_REG_VALUE (0x0u)
#define UART_PL011_DEFAULT_FBRD_REG_VALUE (0x0u)
/* Clear UARTLCR */
#define UART_PL011_DEFAULT_LCR_H_VALUE (0x0u)
#define UART_PL011_DEFAULT_CTRL_REG_VALUE (0x0300u)
#define UART_PL011_DEFAULT_IFLS_REG_VALUE ( \
UART_PL011_RX_FIFO_LVL_1_2 \
| UART_PL011_TX_FIFO_LVL_7_8)
/* Clear interrupt mask */
#define UART_PL011_DEFAULT_IMSC_REG_VALUE (0x0u)
/* Clear interrupt */
#define UART_PL011_DEFAULT_ICR_VALUE (0x7FFu)
#define UART_PL011_DEFAULT_DMACR_VALUE (0x0u)
#define FREQ_IRLPBAUD16_MIN (1420000u) /* 1.42 MHz */
#define FREQ_IRLPBAUD16_MAX (2120000u) /* 2.12 MHz */
#define SAMPLING_FACTOR (16u)
#define UART_PL011_FBRD_WIDTH (6u)
/**
* \brief ARM UART PL011 error enumeration types
*/
typedef enum UartPl011Error {
UART_PL011_ERR_NONE = (0x0u),
UART_PL011_ERR_RX_FRAME = UART_PL011_RSR_FRAMING_ERROR_MASK,
UART_PL011_ERR_RX_PARITY = UART_PL011_RSR_PARITY_ERROR_MASK,
UART_PL011_ERR_RX_BREAK = UART_PL011_RSR_BREAK_ERROR_MASK,
UART_PL011_ERR_RX_OVERFLOW = UART_PL011_RSR_OVERRUN_ERROR_MASK,
UART_PL011_ERR_INVALID_ARG = (UART_PL011_RSR_RX_ERROR_MASK + 1),
UART_PL011_ERR_NOT_READY,
UART_PL011_ERR_INVALID_BAUD,
UART_PL011_ERR_NOT_INIT,
} UartPl011Error;
static inline void UartPl011Enable(struct UartRegisterMap *regMap)
{
regMap->cr |= UART_PL011_CR_UARTEN_MASK;
}
static inline void UartPl011Disable(struct UartRegisterMap *regMap)
{
regMap->cr &= ~UART_PL011_CR_UARTEN_MASK;
}
static inline bool UartPl011IsEnabled(struct UartRegisterMap *regMap)
{
return (bool)(regMap->cr & UART_PL011_CR_UARTEN_MASK);
}
static inline bool UartPl011IsBusy(struct UartRegisterMap *regMap)
{
return (bool)(regMap->fr & UART_PL011_FR_BUSY_MASK);
}
void UartPl011SetLcrBits(struct UartRegisterMap *regMap, uint32_t bits);
static inline void UartPl011Write(struct UartRegisterMap *regMap, uint8_t byte)
{
while (UartPl011IsBusy(regMap));
regMap->dr = byte;
}
UartPl011Error UartPl011SetBaudrate(struct UartRegisterMap *regMap, uint32_t clk, uint32_t baudrate);
void UartPl011SetDataFormat(struct UartRegisterMap *regMap, uint32_t wordLen, uint32_t parity, uint32_t stopBits);
void UartPl011ResetRegisters(struct UartRegisterMap *regMap);
static inline void UartPl011EnableFifo(struct UartRegisterMap *regMap)
{
UartPl011SetLcrBits(regMap, UART_PL011_LCR_H_FEN_MASK);
}
#ifdef __cplusplus
}
#endif
#endif /* UART_PL011_SAMPLE_H */
+22
View File
@@ -0,0 +1,22 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
#
# HDF is dual licensed: you can use it either under the terms of
# the GPL, or the BSD license, at your option.
# See the LICENSE file in the root of this repository for complete details.
import("//drivers/adapter/khdf/liteos/hdf.gni")
module_switch = defined(LOSCFG_DRIVERS_HDF_PLATFORM_UART_SAMPLE)
module_name = "hdf_uart_sample"
hdf_driver(module_name) {
FRAMEWORK_UART_ROOT = "//drivers/framework/sample/platform/uart/src"
sources = [
"$FRAMEWORK_UART_ROOT/buf_fifo.c",
"$FRAMEWORK_UART_ROOT/uart_dev_sample.c",
"$FRAMEWORK_UART_ROOT/uart_dispatch_sample.c",
"$FRAMEWORK_UART_ROOT/uart_pl011_sample.c",
"$FRAMEWORK_UART_ROOT/uart_sample.c",
]
include_dirs = [ "//drivers/framework/sample/platform/uart/include/" ]
}
+24
View File
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "buf_fifo.h"
bool BufferFifoInit(struct BufferFifo *fifo, uint8_t *fifoBuffer, uint16_t fifoSize)
{
if (fifoBuffer == NULL) {
return false;
}
if (!IsPowerOfTwo(fifoSize)) {
return false;
}
fifo->buffer = fifoBuffer;
fifo->bufSizeMask = fifoSize - 1;
fifo->readPosition = 0;
fifo->writePosition = 0;
return true;
}
+191
View File
@@ -0,0 +1,191 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "uart_dev_sample.h"
#include "fs/fs.h"
#include "securec.h"
#include "user_copy.h"
#include "hdf_log.h"
#include "osal_mem.h"
#include "uart_pl011_sample.h"
#define HDF_LOG_TAG uart_dev_sample
#define HDF_UART_FS_MODE 0660
static int32_t UartSampleDevOpen(struct file *filep)
{
struct UartHost *host = NULL;
if (filep == NULL || filep->f_vnode == NULL) {
return HDF_ERR_INVALID_PARAM;
}
struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
host = (struct UartHost *)drv->priv;
if (host == NULL) {
HDF_LOGE("%s: host is NULL", __func__);
return HDF_ERR_INVALID_PARAM;
}
HDF_LOGI("%s: open uart%d success", __func__, host->num);
return HDF_SUCCESS;
}
static int32_t UartSampleRelease(struct file *filep)
{
struct UartHost *host = NULL;
if (filep == NULL || filep->f_vnode == NULL) {
return HDF_ERR_INVALID_PARAM;
}
struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
host = (struct UartHost *)drv->priv;
if (host == NULL) {
HDF_LOGE("%s: host is NULL", __func__);
return HDF_ERR_INVALID_PARAM;
}
HDF_LOGI("%s: close uart%d success", __func__, host->num);
return HDF_SUCCESS;
}
static ssize_t UartSampleRead(struct file *filep, char *buf, size_t count)
{
int32_t ret;
uint8_t *tmpBuf = NULL;
struct UartHost *host = NULL;
if (filep == NULL || filep->f_vnode == NULL) {
return HDF_ERR_INVALID_PARAM;
}
struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
host = (struct UartHost *)drv->priv;
if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)buf, count)) {
tmpBuf = (uint8_t *)OsalMemCalloc(count);
if (tmpBuf == NULL) {
HDF_LOGE("%s: OsalMemCalloc error", __func__);
return HDF_ERR_MALLOC_FAIL;
}
ret = UartHostRead(host, tmpBuf, count);
if (ret == HDF_SUCCESS) {
ret = LOS_ArchCopyToUser(buf, tmpBuf, count);
}
OsalMemFree(tmpBuf);
return ret;
} else {
return UartHostRead(host, (uint8_t *)buf, count);
}
}
static ssize_t UartSampleWrite(struct file *filep, const char *buf, size_t count)
{
int32_t ret;
uint8_t *tmpBuf = NULL;
struct UartHost *host = NULL;
if (filep == NULL || filep->f_vnode == NULL) {
return HDF_ERR_INVALID_PARAM;
}
struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
host = (struct UartHost *)drv->priv;
if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)buf, count)) {
tmpBuf = (uint8_t *)OsalMemCalloc(count);
if (tmpBuf == NULL) {
HDF_LOGE("%s: OsalMemCalloc error", __func__);
return HDF_ERR_MALLOC_FAIL;
}
ret = LOS_ArchCopyFromUser(tmpBuf, buf, count);
if (ret != LOS_OK) {
OsalMemFree(tmpBuf);
return ret;
}
ret = UartHostWrite(host, tmpBuf, count);
OsalMemFree(tmpBuf);
return ret;
} else {
return UartHostWrite(host, (uint8_t *)buf, count);
}
}
static int32_t UartSampleDevIoctl(struct file *filep, int32_t cmd, unsigned long arg)
{
int32_t ret = HDF_FAILURE;
struct UartHost *host = NULL;
if (filep == NULL || filep->f_vnode == NULL) {
return HDF_ERR_INVALID_PARAM;
}
struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
host = (struct UartHost *)drv->priv;
if (host->priv == NULL) {
return HDF_ERR_INVALID_PARAM;
}
switch (cmd) {
case UART_CFG_BAUDRATE:
ret = UartHostSetBaud(host, arg);
break;
default:
HDF_LOGE("%s cmd %d not support", __func__, cmd);
ret = HDF_ERR_NOT_SUPPORT;
break;
}
return ret;
}
const struct file_operations_vfs g_uartSampleDevFops = {
.open = UartSampleDevOpen,
.close = UartSampleRelease,
.read = UartSampleRead,
.write = UartSampleWrite,
.ioctl = UartSampleDevIoctl,
};
#define MAX_DEV_NAME_SIZE 32
static void AddRemoveUartDev(struct UartHost *host, bool add)
{
int32_t ret;
char *devName = NULL;
if (host == NULL || host->priv == NULL) {
HDF_LOGW("%s: invalid parameter", __func__);
return;
}
devName = (char *)OsalMemCalloc(sizeof(char) * (MAX_DEV_NAME_SIZE + 1));
if (devName == NULL) {
HDF_LOGE("%s: OsalMemCalloc error", __func__);
return;
}
ret = snprintf_s(devName, MAX_DEV_NAME_SIZE + 1, MAX_DEV_NAME_SIZE, "/dev/uartdev-%d", host->num);
if (ret < 0) {
HDF_LOGE("%s: snprintf_s failed", __func__);
OsalMemFree(devName);
return;
}
if (add) {
if (register_driver(devName, &g_uartSampleDevFops, HDF_UART_FS_MODE, host)) {
HDF_LOGE("%s: gen /dev/uartdev-%d fail!", __func__, host->num);
OsalMemFree(devName);
return;
}
} else {
if (unregister_driver(devName)) {
HDF_LOGE("%s: remove /dev/uartdev-%d fail!", __func__, host->num);
OsalMemFree(devName);
return;
}
}
OsalMemFree(devName);
}
void AddUartDevice(struct UartHost *host)
{
AddRemoveUartDev(host, true);
}
void RemoveUartDevice(struct UartHost *host)
{
AddRemoveUartDev(host, false);
}
+67
View File
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "uart_core.h"
#include "uart_dispatch_sample.h"
#include "hdf_log.h"
#include "hdf_sbuf.h"
#include "osal_mem.h"
#include "uart_pl011_sample.h"
#define HDF_LOG_TAG uart_dispatch_sample
static int32_t SampleDispatchWrite(struct UartDevice *device, struct HdfSBuf *txBuf)
{
uint32_t idx;
uint32_t dataSize = 0;
const uint8_t *data = NULL;
struct UartRegisterMap *regMap = (struct UartRegisterMap *)device->resource.physBase;
if (regMap == NULL) {
HDF_LOGE("%s: regMap is NULL", __func__);
return HDF_FAILURE;
}
if (!HdfSbufReadBuffer(txBuf, (const void **)&data, &dataSize)) {
HDF_LOGE("%s: Failed to read sbuf", __func__);
return HDF_FAILURE;
}
regMap = (struct UartRegisterMap *)device->resource.physBase;
for (idx = 0; idx < dataSize; idx++) {
UartPl011Write(regMap, data[idx]);
}
return HDF_SUCCESS;
}
int32_t SampleDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply)
{
int32_t result = HDF_FAILURE;
if (client == NULL || client->device == NULL) {
HDF_LOGE("%s: client or client->device is NULL", __func__);
return result;
}
struct UartHost *uartHost = (struct UartHost *)client->device->service;
if (uartHost == NULL) {
HDF_LOGE("%s: uartHost is NULL", __func__);
return result;
}
struct UartDevice *uartDevice = (struct UartDevice *)uartHost->priv;
if (uartDevice == NULL) {
HDF_LOGE("%s: uartDevice is NULL", __func__);
return result;
}
switch (cmdId) {
case UART_WRITE: {
result = SampleDispatchWrite(uartDevice, data);
break;
}
default:
break;
}
return result;
}
+90
View File
@@ -0,0 +1,90 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "uart_pl011_sample.h"
void UartPl011SetLcrBits(struct UartRegisterMap *regMap, uint32_t bits)
{
bool uartEnabled = UartPl011IsEnabled(regMap);
/* UART must be disabled before UARTLCR_H are reprogrammed */
UartPl011Disable(regMap);
regMap->lcr |= (bits);
/* Restore uart enable state */
if (uartEnabled) {
UartPl011Enable(regMap);
}
}
void UartPl011UpdateLcr(struct UartRegisterMap *regMap)
{
bool uartEnabled = UartPl011IsEnabled(regMap);
/* UART must be disabled before UARTLCR_H are reprogrammed */
UartPl011Disable(regMap);
regMap->lcr = regMap->lcr;
/* restore uart enable state */
if (uartEnabled) {
UartPl011Enable(regMap);
}
}
UartPl011Error UartPl011SetBaudrate(struct UartRegisterMap *regMap, uint32_t clk, uint32_t baudrate)
{
if (baudrate == 0) {
return UART_PL011_ERR_INVALID_ARG;
}
uint32_t value = SAMPLING_FACTOR * baudrate;
uint32_t divider = clk / value;
uint32_t remainder = clk % value;
uint32_t fraction;
value = (SAMPLING_FACTOR * remainder) / baudrate;
fraction = (value >> 1) + (value & 1);
regMap->ibrd = divider;
regMap->fbrd = fraction;
/* to internally update the contents of UARTIBRD or
* UARTFBRD, a UARTLCR_H write must always be performed at the end.
*/
UartPl011UpdateLcr(regMap);
return UART_PL011_ERR_NONE;
}
void UartPl011SetDataFormat(
struct UartRegisterMap *regMap, uint32_t wordLen, uint32_t parity, uint32_t stopBits)
{
bool uartEnabled = UartPl011IsEnabled(regMap);
uint32_t lcr = regMap->lcr & (~UART_PL011_DATA_FORMAT_MASK);
lcr |= wordLen & UART_PL011_LCR_H_WLEN_MASK;
lcr |= parity & UART_PL011_LCR_H_PARITY_MASK;
lcr |= stopBits & UART_PL011_LCR_H_STOPBIT_MASK;
/* UART must be disabled before UARTLCR_H are reprogrammed */
UartPl011Disable(regMap);
regMap->lcr = lcr;
if (uartEnabled) {
UartPl011Enable(regMap);
}
}
void UartPl011ResetRegisters(struct UartRegisterMap *regMap)
{
regMap->cr = UART_PL011_DEFAULT_CTRL_REG_VALUE;
regMap->dr = UART_PL011_DEFAULT_DATA_REG_VALUE;
/* Clear all the errors */
regMap->ecr = UART_PL011_DEFAULT_ECR_VALUE;
regMap->ilpr = UART_PL011_DEFAULT_ILPR_VALUE;
regMap->ibrd = UART_PL011_DEFAULT_IBRD_REG_VALUE;
regMap->fbrd = UART_PL011_DEFAULT_FBRD_REG_VALUE;
regMap->lcr = UART_PL011_DEFAULT_LCR_H_VALUE;
regMap->ifls = UART_PL011_DEFAULT_IFLS_REG_VALUE;
/* Clear all interrupt mask */
regMap->imsc = UART_PL011_DEFAULT_IMSC_REG_VALUE;
/* Clear all interrupts */
regMap->icr = UART_PL011_DEFAULT_ICR_VALUE;
regMap->dmacr = UART_PL011_DEFAULT_DMACR_VALUE;
}
+344
View File
@@ -0,0 +1,344 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "device_resource_if.h"
#include "buf_fifo.h"
#include "hdf_device_desc.h"
#include "hdf_log.h"
#include "hisoc/uart.h"
#include "osal_io.h"
#include "osal_mem.h"
#include "uart_core.h"
#include "uart_dev_sample.h"
#include "uart_dispatch_sample.h"
#include "uart_pl011_sample.h"
#define HDF_LOG_TAG uart_sample
#define UART_RX_FIFO_SIZE 128
static uint8_t g_fifoBuffer[UART_RX_FIFO_SIZE] = {0};
/* HdfDriverEntry method definitions */
static int32_t SampleUartDriverBind(struct HdfDeviceObject *device);
static int32_t SampleUartDriverInit(struct HdfDeviceObject *device);
static void SampleUartDriverRelease(struct HdfDeviceObject *device);
/* HdfDriverEntry definitions */
struct HdfDriverEntry g_sampleUartDriverEntry = {
.moduleVersion = 1,
.moduleName = "UART_SAMPLE",
.Bind = SampleUartDriverBind,
.Init = SampleUartDriverInit,
.Release = SampleUartDriverRelease,
};
// Initialize HdfDriverEntry
HDF_INIT(g_sampleUartDriverEntry);
/* UartHostMethod method definitions */
static int32_t SampleUartHostInit(struct UartHost *host);
static int32_t SampleUartHostDeinit(struct UartHost *host);
static int32_t SampleUartHostWrite(struct UartHost *host, uint8_t *data, uint32_t size);
static int32_t SampleUartHostSetBaud(struct UartHost *host, uint32_t baudRate);
static int32_t SampleUartHostGetBaud(struct UartHost *host, uint32_t *baudRate);
/* UartHostMethod definitions */
struct UartHostMethod g_sampleUartHostMethod = {
.Init = SampleUartHostInit,
.Deinit = SampleUartHostDeinit,
.Read = NULL,
.Write = SampleUartHostWrite,
.SetBaud = SampleUartHostSetBaud,
.GetBaud = SampleUartHostGetBaud,
.SetAttribute = NULL,
.GetAttribute = NULL,
.SetTransMode = NULL,
};
/* UartHostMethod implementations */
static int32_t SampleUartHostInit(struct UartHost *host)
{
HDF_LOGD("%s: Enter", __func__);
if (host == NULL) {
HDF_LOGW("%s: invalid parameter", __func__);
return HDF_ERR_INVALID_PARAM;
}
return HDF_SUCCESS;
}
static int32_t SampleUartHostDeinit(struct UartHost *host)
{
HDF_LOGD("%s: Enter", __func__);
if (host == NULL) {
HDF_LOGW("%s: invalid parameter", __func__);
return HDF_ERR_INVALID_PARAM;
}
return HDF_SUCCESS;
}
static int32_t SampleUartHostWrite(struct UartHost *host, uint8_t *data, uint32_t size)
{
uint32_t idx;
struct UartRegisterMap *regMap = NULL;
struct UartDevice *device = NULL;
HDF_LOGD("%s: Enter", __func__);
if (host == NULL || data == NULL || size == 0) {
HDF_LOGW("%s: invalid parameter", __func__);
return HDF_ERR_INVALID_PARAM;
}
device = (struct UartDevice *)host->priv;
if (device == NULL) {
HDF_LOGW("%s: device is NULL", __func__);
return HDF_ERR_INVALID_PARAM;
}
regMap = (struct UartRegisterMap *)device->resource.physBase;
for (idx = 0; idx < size; idx++) {
UartPl011Write(regMap, data[idx]);
}
return HDF_SUCCESS;
}
static int32_t SampleUartHostSetBaud(struct UartHost *host, uint32_t baudRate)
{
struct UartDevice *device = NULL;
struct UartRegisterMap *regMap = NULL;
UartPl011Error err;
HDF_LOGD("%s: Enter", __func__);
if (host == NULL) {
HDF_LOGW("%s: invalid parameter", __func__);
return HDF_ERR_INVALID_PARAM;
}
device = (struct UartDevice *)host->priv;
if (device == NULL) {
HDF_LOGW("%s: device is NULL", __func__);
return HDF_ERR_INVALID_PARAM;
}
regMap = (struct UartRegisterMap *)device->resource.physBase;
if (device->state != UART_DEVICE_INITIALIZED) {
return UART_PL011_ERR_NOT_INIT;
}
if (baudRate == 0) {
return UART_PL011_ERR_INVALID_BAUD;
}
err = UartPl011SetBaudrate(regMap, device->uartClk, baudRate);
if (err == UART_PL011_ERR_NONE) {
device->baudrate = baudRate;
}
return err;
}
static int32_t SampleUartHostGetBaud(struct UartHost *host, uint32_t *baudRate)
{
struct UartDevice *device = NULL;
HDF_LOGD("%s: Enter", __func__);
if (host == NULL) {
HDF_LOGW("%s: invalid parameter", __func__);
return HDF_ERR_INVALID_PARAM;
}
device = (struct UartDevice *)host->priv;
if (device == NULL) {
HDF_LOGW("%s: device is NULL", __func__);
return HDF_ERR_INVALID_PARAM;
}
*baudRate = device->baudrate;
return HDF_SUCCESS;
}
static int InitUartDevice(struct UartDevice *device)
{
UartPl011Error err;
struct UartResource *resource = &device->resource;
struct UartRegisterMap *regMap = (struct UartRegisterMap *)resource->physBase;
if ((resource->uartClk == 0) || (resource->baudrate == 0)) {
return HDF_ERR_INVALID_PARAM;
}
/* Updating the system clock */
device->uartClk = resource->uartClk;
uart_clk_cfg(0, true);
/* clear and reset registers. */
UartPl011ResetRegisters(regMap);
/* set baud rate as device config */
err = UartPl011SetBaudrate(regMap, resource->uartClk, resource->baudrate);
if (err != UART_PL011_ERR_NONE) {
return HDF_FAILURE;
}
/* set the data format as device config */
UartPl011SetDataFormat(regMap, resource->wlen, resource->parity, resource->stopBit);
/* Enabling the FIFOs */
UartPl011EnableFifo(regMap);
UartPl011Enable(regMap);
BufferFifoInit(&device->rxFifo, g_fifoBuffer, UART_RX_FIFO_SIZE);
device->state = UART_DEVICE_INITIALIZED;
return HDF_SUCCESS;
}
static uint32_t GetUartDeviceResource(
struct UartDevice *device, const struct DeviceResourceNode *resourceNode)
{
struct UartResource *resource = &device->resource;
struct DeviceResourceIface *dri = NULL;
dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
if (dri == NULL || dri->GetUint32 == NULL) {
HDF_LOGE("DeviceResourceIface is invalid");
return HDF_FAILURE;
}
if (dri->GetUint32(resourceNode, "num", &resource->num, 0) != HDF_SUCCESS) {
HDF_LOGE("uart config read num fail");
return HDF_FAILURE;
}
if (dri->GetUint32(resourceNode, "base", &resource->base, 0) != HDF_SUCCESS) {
HDF_LOGE("uart config read base fail");
return HDF_FAILURE;
}
resource->physBase = (unsigned long)OsalIoRemap(resource->base, 0x48);
if (resource->physBase == 0) {
HDF_LOGE("uart config fail to remap physBase");
return HDF_FAILURE;
}
if (dri->GetUint32(resourceNode, "irqNum", &resource->irqNum, 0) != HDF_SUCCESS) {
HDF_LOGE("uart config read irqNum fail");
return HDF_FAILURE;
}
if (dri->GetUint32(resourceNode, "baudrate", &resource->baudrate, 0) != HDF_SUCCESS) {
HDF_LOGE("uart config read baudrate fail");
return HDF_FAILURE;
}
if (dri->GetUint32(resourceNode, "wlen", &resource->wlen, 0) != HDF_SUCCESS) {
HDF_LOGE("uart config read wlen fail");
return HDF_FAILURE;
}
if (dri->GetUint32(resourceNode, "parity", &resource->parity, 0) != HDF_SUCCESS) {
HDF_LOGE("uart config read parity fail");
return HDF_FAILURE;
}
if (dri->GetUint32(resourceNode, "stopBit", &resource->stopBit, 0) != HDF_SUCCESS) {
HDF_LOGE("uart config read stopBit fail");
return HDF_FAILURE;
}
if (dri->GetUint32(resourceNode, "uartClk", &resource->uartClk, 0) != HDF_SUCCESS) {
HDF_LOGE("uart config read uartClk fail");
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static int32_t AttachUartDevice(struct UartHost *host, struct HdfDeviceObject *device)
{
int32_t ret;
struct UartDevice *uartDevice = NULL;
if (device->property == NULL) {
HDF_LOGW("%s: property is NULL", __func__);
return HDF_FAILURE;
}
uartDevice = (struct UartDevice *)OsalMemCalloc(sizeof(struct UartDevice));
if (uartDevice == NULL) {
HDF_LOGE("%s: OsalMemCalloc uartDevice error", __func__);
return HDF_ERR_MALLOC_FAIL;
}
ret = GetUartDeviceResource(uartDevice, device->property);
if (ret != HDF_SUCCESS) {
(void)OsalMemFree(uartDevice);
return HDF_FAILURE;
}
host->num = uartDevice->resource.num;
host->priv = uartDevice;
AddUartDevice(host);
return InitUartDevice(uartDevice);
}
static void DeinitUartDevice(struct UartDevice *device)
{
struct UartRegisterMap *regMap = (struct UartRegisterMap *)device->resource.physBase;
/* wait for uart enter idle. */
while (UartPl011IsBusy(regMap));
UartPl011ResetRegisters(regMap);
uart_clk_cfg(0, false);
OsalIoUnmap((void *)device->resource.physBase);
device->state = UART_DEVICE_UNINITIALIZED;
}
static void DetachUartDevice(struct UartHost *host)
{
struct UartDevice *uartDevice = NULL;
if (host->priv == NULL) {
HDF_LOGW("%s: invalid parameter", __func__);
return;
}
uartDevice = host->priv;
DeinitUartDevice(uartDevice);
(void)OsalMemFree(uartDevice);
host->priv = NULL;
}
/* HdfDriverEntry implementations */
static int32_t SampleUartDriverBind(struct HdfDeviceObject *device)
{
struct UartHost *uartHost = NULL;
HDF_LOGD("%s: Enter", __func__);
if (device == NULL) {
return HDF_ERR_INVALID_OBJECT;
}
uartHost = UartHostCreate(device);
if (uartHost == NULL) {
HDF_LOGE("%s: UartHostCreate failed", __func__);
return HDF_FAILURE;
}
uartHost->service.Dispatch = SampleDispatch;
return HDF_SUCCESS;
}
static int32_t SampleUartDriverInit(struct HdfDeviceObject *device)
{
int32_t ret;
struct UartHost *host = NULL;
HDF_LOGD("%s: Enter", __func__);
if (device == NULL) {
HDF_LOGE("%s: device is NULL", __func__);
return HDF_ERR_INVALID_OBJECT;
}
host = UartHostFromDevice(device);
if (host == NULL) {
HDF_LOGE("%s: host is NULL", __func__);
return HDF_FAILURE;
}
ret = AttachUartDevice(host, device);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: attach error", __func__);
return HDF_FAILURE;
}
host->method = &g_sampleUartHostMethod;
return ret;
}
static void SampleUartDriverRelease(struct HdfDeviceObject *device)
{
struct UartHost *host = NULL;
HDF_LOGD("%s: Enter", __func__);
if (device == NULL) {
HDF_LOGE("%s: device is NULL", __func__);
return;
}
host = UartHostFromDevice(device);
if (host == NULL) {
HDF_LOGE("%s: host is NULL", __func__);
return;
}
if (host->priv != NULL) {
DetachUartDevice(host);
}
UartHostDestroy(host);
}