blob: a3e30520620f65f1d90711f148ce164f292f949a [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 <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ddk/device.h>
#include <ddk/debug.h>
#include <ddk/protocol/sdmmc.h>
#include <hw/sdio.h>
#include "sdmmc.h"
#include "sdio.h"
zx_status_t sdio_enable_interrupt(void *ctx, uint8_t fn_idx) {
zx_status_t st = ZX_OK;
sdmmc_device_t *dev = ctx;
if (!sdio_fn_idx_valid(fn_idx)) {
return ZX_ERR_INVALID_ARGS;
}
sdio_function_t *func = &(dev->sdio_dev.funcs[fn_idx]);
if (func->intr_enabled) {
return ZX_OK;
}
uint8_t intr_byte;
st = sdio_io_rw_direct(dev, false, 0, SDIO_CIA_CCCR_IEN_INTR_EN_ADDR, 0,
&intr_byte);
if (st != ZX_OK) {
zxlogf(ERROR, "sdio_enable_interrupt: Failed to enable interrupt for fn: %d status: %d\n",
fn_idx, st);
return st;
}
// Enable fn intr
intr_byte |= 1 << fn_idx;
// Enable master intr
intr_byte |= 1;
st = sdio_io_rw_direct(dev, true, 0, SDIO_CIA_CCCR_IEN_INTR_EN_ADDR,
intr_byte, NULL);
if (st != ZX_OK) {
zxlogf(ERROR, "sdio_enable_interrupt: Failed to enable interrupt for fn: %d status: %d\n",
fn_idx, st);
return st;
}
func->intr_enabled = true;
zxlogf(TRACE, "sdio_enable_interrupt: Interrupt enabled for fn %d\n", fn_idx);
return ZX_OK;
}
zx_status_t sdio_disable_interrupt(void *ctx, uint8_t fn_idx) {
zx_status_t st = ZX_OK;
sdmmc_device_t *dev = ctx;
if (!sdio_fn_idx_valid(fn_idx)) {
return ZX_ERR_INVALID_ARGS;
}
sdio_function_t *func = &(dev->sdio_dev.funcs[fn_idx]);
if (!(func->intr_enabled)) {
zxlogf(ERROR, "sdio_disable_interrupt: Interrupt is not enabled for %d\n", fn_idx);
return ZX_ERR_BAD_STATE;
}
uint8_t intr_byte;
st = sdio_io_rw_direct(dev, false, 0, SDIO_CIA_CCCR_IEN_INTR_EN_ADDR, 0,
&intr_byte);
if (st != ZX_OK) {
zxlogf(ERROR, "sdio_disable_interrupt: Failed reading intr enable reg."
" func: %d status: %d\n", fn_idx, st);
return st;
}
intr_byte &= ~(1 << fn_idx);
if (!(intr_byte & SDIO_ALL_INTR_ENABLED_MASK)) {
//disable master as well
intr_byte = 0;
}
st = sdio_io_rw_direct(dev, true, 0, SDIO_CIA_CCCR_IEN_INTR_EN_ADDR, intr_byte, NULL);
if (st != ZX_OK) {
zxlogf(ERROR, "sdio_disable_interrupt: Error writing to intr enable reg."
" func: %d status: %d\n", fn_idx, st);
return st;
}
func->intr_enabled = false;
zxlogf(TRACE, "sdio_enable_interrupt: Interrupt disabled for fn %d\n", fn_idx);
return ZX_OK;
}