#include <sys/types.h>
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/endian.h>
#include <dev/mmc/mmcreg.h>
#include <dev/sdio/sdiob.h>
#include <dev/sdio/sdio_subr.h>
#include "sdio_if.h"
static int
sdio_set_bool_for_func(device_t dev, uint32_t addr, uint8_t fn, bool enable)
{
device_t pdev;
int error;
uint8_t val;
bool enabled;
pdev = device_get_parent(dev);
error = SDIO_READ_DIRECT(pdev, 0, addr, &val);
if (error != 0)
return (error);
enabled = (val & (1 << fn)) ? true : false;
if (enabled == enable)
return (0);
if (enable)
val |= (1 << fn);
else
val &= ~(1 << fn);
error = SDIO_WRITE_DIRECT(pdev, 0, addr, val);
return (error);
}
int
sdio_enable_func(struct sdio_func *f)
{
return (sdio_set_bool_for_func(f->dev, SD_IO_CCCR_FN_ENABLE,
f->fn, true));
}
int
sdio_disable_func(struct sdio_func *f)
{
return (sdio_set_bool_for_func(f->dev, SD_IO_CCCR_FN_ENABLE,
f->fn, false));
}
int
sdio_set_block_size(struct sdio_func *f, uint16_t bs)
{
device_t pdev;
int error;
uint32_t addr;
uint16_t v;
if (bs > f->max_blksize)
return (EOPNOTSUPP);
if (!sdio_get_support_multiblk(f->dev))
return (EOPNOTSUPP);
pdev = device_get_parent(f->dev);
addr = SD_IO_FBR_START * f->fn + SD_IO_FBR_IOBLKSZ;
v = htole16(bs);
error = SDIO_WRITE_DIRECT(pdev, 0, addr, v & 0xff);
if (error == 0)
error = SDIO_WRITE_DIRECT(pdev, 0, addr + 1,
(v >> 8) & 0xff);
if (error == 0)
f->cur_blksize = bs;
return (error);
}
uint8_t
sdio_read_1(struct sdio_func *f, uint32_t addr, int *err)
{
int error;
uint8_t v;
error = SDIO_READ_DIRECT(device_get_parent(f->dev), f->fn, addr, &v);
if (error) {
if (err != NULL)
*err = error;
return (0xff);
} else {
if (err != NULL)
*err = 0;
return (v);
}
}
void
sdio_write_1(struct sdio_func *f, uint32_t addr, uint8_t val, int *err)
{
int error;
error = SDIO_WRITE_DIRECT(device_get_parent(f->dev), f->fn, addr, val);
if (err != NULL)
*err = error;
}
uint16_t
sdio_read_2(struct sdio_func *f, uint32_t addr, int *err)
{
int error;
uint16_t v;
error = SDIO_READ_EXTENDED(device_get_parent(f->dev), f->fn, addr,
sizeof(v), (uint8_t *)&v, true);
if (error) {
if (err != NULL)
*err = error;
return (0xffff);
} else {
if (err != NULL)
*err = 0;
return (le16toh(v));
}
}
void
sdio_write_2(struct sdio_func *f, uint32_t addr, uint16_t val, int *err)
{
int error;
error = SDIO_WRITE_EXTENDED(device_get_parent(f->dev), f->fn, addr,
sizeof(val), (uint8_t *)&val, true);
if (err != NULL)
*err = error;
}
uint32_t
sdio_read_4(struct sdio_func *f, uint32_t addr, int *err)
{
int error;
uint32_t v;
error = SDIO_READ_EXTENDED(device_get_parent(f->dev), f->fn, addr,
sizeof(v), (uint8_t *)&v, true);
if (error) {
if (err != NULL)
*err = error;
return (0xffffffff);
} else {
if (err != NULL)
*err = 0;
return (le32toh(v));
}
}
void
sdio_write_4(struct sdio_func *f, uint32_t addr, uint32_t val, int *err)
{
int error;
error = SDIO_WRITE_EXTENDED(device_get_parent(f->dev), f->fn, addr,
sizeof(val), (uint8_t *)&val, true);
if (err != NULL)
*err = error;
}
uint8_t
sdio_f0_read_1(struct sdio_func *f, uint32_t addr, int *err)
{
int error;
uint8_t v;
error = SDIO_READ_DIRECT(device_get_parent(f->dev), 0, addr, &v);
if (error) {
if (err != NULL)
*err = error;
return (0xff);
} else {
if (err != NULL)
*err = 0;
return (v);
}
}
void
sdio_f0_write_1(struct sdio_func *f, uint32_t addr, uint8_t val, int *err)
{
int error;
error = SDIO_WRITE_DIRECT(device_get_parent(f->dev), 0, addr, val);
if (err != NULL)
*err = error;
}