blob: 33e50017353cab14b9f1aa42fce8d8ddd5a33b53 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <threads.h>
#include <ddk/io-buffer.h>
#include <ddk/protocol/platform-device.h>
#include <ddk/protocol/serial-impl.h>
#include <ddk/protocol/serial.h>
#include <ddktl/device.h>
#include <ddktl/protocol/serial-impl.h>
#include <fbl/function.h>
#include <fbl/mutex.h>
#include <lib/zx/interrupt.h>
#include <zircon/thread_annotations.h>
#include <zircon/types.h>
namespace serial {
class AmlUart;
using DeviceType = ddk::Device<AmlUart, ddk::Unbindable>;
class AmlUart : public DeviceType,
public ddk::SerialImplProtocol<AmlUart> {
public:
// Spawns device node.
static zx_status_t Create(zx_device_t* parent);
// Device protocol implementation.
void DdkUnbind() {
DdkRemove();
}
void DdkRelease() {
SerialImplEnable(false);
io_buffer_release(&mmio_);
delete this;
}
// Serial protocol implementation.
zx_status_t SerialImplGetInfo(serial_port_info_t* info);
zx_status_t SerialImplConfig(uint32_t baud_rate, uint32_t flags);
zx_status_t SerialImplEnable(bool enable);
zx_status_t SerialImplRead(void* buf, size_t length, size_t* out_actual);
zx_status_t SerialImplWrite(const void* buf, size_t length, size_t* out_actual);
zx_status_t SerialImplSetNotifyCallback(const serial_notify_t* cb);
private:
using Callback = fbl::Function<void(uint32_t)>;
explicit AmlUart(zx_device_t* parent, const platform_device_protocol_t& pdev,
const serial_port_info_t& serial_port_info, io_buffer_t mmio)
: DeviceType(parent), pdev_(pdev), serial_port_info_(serial_port_info), mmio_(mmio) {}
// Reads the current state from the status register and calls notify_cb if it has changed.
uint32_t ReadStateAndNotify();
void EnableLocked(bool enable) TA_REQ(enable_lock_);
int IrqThread();
const platform_device_protocol_t pdev_;
const serial_port_info_t serial_port_info_;
io_buffer_t mmio_;
zx::interrupt irq_;
thrd_t irq_thread_ TA_GUARDED(enable_lock_);
bool enabled_ TA_GUARDED(enable_lock_) = false;
Callback notify_cb_ TA_GUARDED(status_lock_) = nullptr;
// Last state we sent to notify_cb.
uint32_t state_ TA_GUARDED(status_lock_) = 0;
// Protects enabling/disabling lifecycle.
fbl::Mutex enable_lock_;
// Protects status register and notify_cb.
fbl::Mutex status_lock_;
};
} // namespace serial