Changeset View
Changeset View
Standalone View
Standalone View
sys/arm/freescale/vybrid/vf_i2c.c
Show First 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | |||||
#include <sys/timeet.h> | #include <sys/timeet.h> | ||||
#include <sys/timetc.h> | #include <sys/timetc.h> | ||||
#include <dev/iicbus/iiconf.h> | #include <dev/iicbus/iiconf.h> | ||||
#include <dev/iicbus/iicbus.h> | #include <dev/iicbus/iicbus.h> | ||||
#include "iicbus_if.h" | #include "iicbus_if.h" | ||||
#include <dev/ofw/openfirm.h> | |||||
#include <dev/ofw/ofw_bus.h> | |||||
#include <dev/ofw/ofw_bus_subr.h> | |||||
#ifdef EXT_RESOURCES | #ifdef EXT_RESOURCES | ||||
#include <dev/extres/clk/clk.h> | #include <dev/extres/clk/clk.h> | ||||
#endif | #endif | ||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <machine/cpu.h> | #include <machine/cpu.h> | ||||
#include <machine/intr.h> | #include <machine/intr.h> | ||||
#include <arm/freescale/vybrid/vf_common.h> | #include <arm/freescale/vybrid/vf_common.h> | ||||
#include <arm/freescale/vybrid/vf_i2c.h> | |||||
#define I2C_IBAD 0x0 /* I2C Bus Address Register */ | #define I2C_IBAD 0x0 /* I2C Bus Address Register */ | ||||
#define I2C_IBFD 0x1 /* I2C Bus Frequency Divider Register */ | #define I2C_IBFD 0x1 /* I2C Bus Frequency Divider Register */ | ||||
#define I2C_IBCR 0x2 /* I2C Bus Control Register */ | #define I2C_IBCR 0x2 /* I2C Bus Control Register */ | ||||
#define IBCR_MDIS (1 << 7) /* Module disable. */ | #define IBCR_MDIS (1 << 7) /* Module disable. */ | ||||
#define IBCR_IBIE (1 << 6) /* I-Bus Interrupt Enable. */ | #define IBCR_IBIE (1 << 6) /* I-Bus Interrupt Enable. */ | ||||
#define IBCR_MSSL (1 << 5) /* Master/Slave mode select. */ | #define IBCR_MSSL (1 << 5) /* Master/Slave mode select. */ | ||||
#define IBCR_TXRX (1 << 4) /* Transmit/Receive mode select. */ | #define IBCR_TXRX (1 << 4) /* Transmit/Receive mode select. */ | ||||
Show All 15 Lines | |||||
#ifdef DEBUG | #ifdef DEBUG | ||||
#define vf_i2c_dbg(_sc, fmt, args...) \ | #define vf_i2c_dbg(_sc, fmt, args...) \ | ||||
device_printf((_sc)->dev, fmt, ##args) | device_printf((_sc)->dev, fmt, ##args) | ||||
#else | #else | ||||
#define vf_i2c_dbg(_sc, fmt, args...) | #define vf_i2c_dbg(_sc, fmt, args...) | ||||
#endif | #endif | ||||
#define HW_UNKNOWN 0x00 | |||||
#define HW_MVF600 0x01 | |||||
#define HW_VF610 0x02 | |||||
static int i2c_repeated_start(device_t, u_char, int); | static int i2c_repeated_start(device_t, u_char, int); | ||||
static int i2c_start(device_t, u_char, int); | static int i2c_start(device_t, u_char, int); | ||||
static int i2c_stop(device_t); | static int i2c_stop(device_t); | ||||
static int i2c_reset(device_t, u_char, u_char, u_char *); | static int i2c_reset(device_t, u_char, u_char, u_char *); | ||||
static int i2c_read(device_t, char *, int, int *, int, int); | static int i2c_read(device_t, char *, int, int *, int, int); | ||||
static int i2c_write(device_t, const char *, int, int *, int); | static int i2c_write(device_t, const char *, int, int *, int); | ||||
static phandle_t i2c_get_node(device_t, device_t); | |||||
struct i2c_div_type { | struct i2c_div_type { | ||||
uint32_t reg_val; | uint32_t reg_val; | ||||
uint32_t div; | uint32_t div; | ||||
}; | }; | ||||
struct i2c_softc { | |||||
struct resource *res[2]; | |||||
bus_space_tag_t bst; | |||||
bus_space_handle_t bsh; | |||||
#ifdef EXT_RESOURCES | |||||
clk_t clock; | |||||
uint32_t freq; | |||||
#endif | |||||
device_t dev; | |||||
device_t iicbus; | |||||
struct mtx mutex; | |||||
uintptr_t hwtype; | |||||
}; | |||||
static struct resource_spec i2c_spec[] = { | static struct resource_spec i2c_spec[] = { | ||||
{ SYS_RES_MEMORY, 0, RF_ACTIVE }, | { SYS_RES_MEMORY, 0, RF_ACTIVE }, | ||||
{ SYS_RES_IRQ, 0, RF_ACTIVE }, | { SYS_RES_IRQ, 0, RF_ACTIVE }, | ||||
{ -1, 0 } | { -1, 0 } | ||||
}; | }; | ||||
#ifdef EXT_RESOURCES | #ifdef EXT_RESOURCES | ||||
static struct i2c_div_type vf610_div_table[] = { | static struct i2c_div_type vf610_div_table[] = { | ||||
{ 0x00, 20 }, { 0x01, 22 }, { 0x02, 24 }, { 0x03, 26 }, | { 0x00, 20 }, { 0x01, 22 }, { 0x02, 24 }, { 0x03, 26 }, | ||||
{ 0x04, 28 }, { 0x05, 30 }, { 0x09, 32 }, { 0x06, 34 }, | { 0x04, 28 }, { 0x05, 30 }, { 0x09, 32 }, { 0x06, 34 }, | ||||
{ 0x0A, 36 }, { 0x0B, 40 }, { 0x0C, 44 }, { 0x0D, 48 }, | { 0x0A, 36 }, { 0x0B, 40 }, { 0x0C, 44 }, { 0x0D, 48 }, | ||||
{ 0x0E, 56 }, { 0x12, 64 }, { 0x13, 72 }, { 0x14, 80 }, | { 0x0E, 56 }, { 0x12, 64 }, { 0x13, 72 }, { 0x14, 80 }, | ||||
{ 0x15, 88 }, { 0x19, 96 }, { 0x16, 104 }, { 0x1A, 112 }, | { 0x15, 88 }, { 0x19, 96 }, { 0x16, 104 }, { 0x1A, 112 }, | ||||
{ 0x17, 128 }, { 0x1D, 160 }, { 0x1E, 192 }, { 0x22, 224 }, | { 0x17, 128 }, { 0x1D, 160 }, { 0x1E, 192 }, { 0x22, 224 }, | ||||
{ 0x1F, 240 }, { 0x23, 256 }, { 0x24, 288 }, { 0x25, 320 }, | { 0x1F, 240 }, { 0x23, 256 }, { 0x24, 288 }, { 0x25, 320 }, | ||||
{ 0x26, 384 }, { 0x2A, 448 }, { 0x27, 480 }, { 0x2B, 512 }, | { 0x26, 384 }, { 0x2A, 448 }, { 0x27, 480 }, { 0x2B, 512 }, | ||||
{ 0x2C, 576 }, { 0x2D, 640 }, { 0x2E, 768 }, { 0x32, 896 }, | { 0x2C, 576 }, { 0x2D, 640 }, { 0x2E, 768 }, { 0x32, 896 }, | ||||
{ 0x2F, 960 }, { 0x33, 1024 }, { 0x34, 1152 }, { 0x35, 1280 }, | { 0x2F, 960 }, { 0x33, 1024 }, { 0x34, 1152 }, { 0x35, 1280 }, | ||||
{ 0x36, 1536 }, { 0x3A, 1792 }, { 0x37, 1920 }, { 0x3B, 2048 }, | { 0x36, 1536 }, { 0x3A, 1792 }, { 0x37, 1920 }, { 0x3B, 2048 }, | ||||
{ 0x3C, 2304 }, { 0x3D, 2560 }, { 0x3E, 3072 }, { 0x3F, 3840 } | { 0x3C, 2304 }, { 0x3D, 2560 }, { 0x3E, 3072 }, { 0x3F, 3840 } | ||||
}; | }; | ||||
#endif | #endif | ||||
static const struct ofw_compat_data i2c_compat_data[] = { | int | ||||
{"fsl,mvf600-i2c", HW_MVF600}, | vf_i2c_attach_common(device_t dev) | ||||
{"fsl,vf610-i2c", HW_VF610}, | |||||
{NULL, HW_UNKNOWN} | |||||
}; | |||||
static int | |||||
i2c_probe(device_t dev) | |||||
{ | { | ||||
struct i2c_softc *sc = device_get_softc(dev); | |||||
if (!ofw_bus_status_okay(dev)) | |||||
return (ENXIO); | |||||
if (!ofw_bus_search_compatible(dev, i2c_compat_data)->ocd_data) | |||||
return (ENXIO); | |||||
device_set_desc(dev, "Vybrid Family Inter-Integrated Circuit (I2C)"); | |||||
return (BUS_PROBE_DEFAULT); | |||||
} | |||||
static int | |||||
i2c_attach(device_t dev) | |||||
{ | |||||
struct i2c_softc *sc; | |||||
#ifdef EXT_RESOURCES | |||||
phandle_t node; | |||||
#endif | |||||
int error; | int error; | ||||
sc = device_get_softc(dev); | |||||
sc->dev = dev; | |||||
sc->hwtype = ofw_bus_search_compatible(dev, i2c_compat_data)->ocd_data; | |||||
#ifdef EXT_RESOURCES | |||||
node = ofw_bus_get_node(dev); | |||||
error = clk_get_by_ofw_index(dev, node, 0, &sc->clock); | |||||
if (error != 0) { | |||||
sc->freq = 0; | |||||
device_printf(dev, "Parent clock not found.\n"); | |||||
} else { | |||||
if (OF_hasprop(node, "clock-frequency")) | |||||
OF_getencprop(node, "clock-frequency", &sc->freq, | |||||
sizeof(sc->freq)); | |||||
else | |||||
sc->freq = 100000; | |||||
} | |||||
#endif | |||||
mtx_init(&sc->mutex, device_get_nameunit(dev), "I2C", MTX_DEF); | mtx_init(&sc->mutex, device_get_nameunit(dev), "I2C", MTX_DEF); | ||||
error = bus_alloc_resources(dev, i2c_spec, sc->res); | error = bus_alloc_resources(dev, i2c_spec, sc->res); | ||||
if (error != 0) { | if (error != 0) { | ||||
mtx_destroy(&sc->mutex); | mtx_destroy(&sc->mutex); | ||||
device_printf(dev, "could not allocate resources\n"); | device_printf(dev, "could not allocate resources\n"); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 361 Lines • ▼ Show 20 Lines | while (*sent < len) { | ||||
(*sent)++; | (*sent)++; | ||||
} | } | ||||
mtx_unlock(&sc->mutex); | mtx_unlock(&sc->mutex); | ||||
return (IIC_NOERR); | return (IIC_NOERR); | ||||
} | } | ||||
static phandle_t | |||||
i2c_get_node(device_t bus, device_t dev) | |||||
{ | |||||
return ofw_bus_get_node(bus); | |||||
} | |||||
static device_method_t i2c_methods[] = { | static device_method_t i2c_methods[] = { | ||||
DEVMETHOD(device_probe, i2c_probe), | |||||
DEVMETHOD(device_attach, i2c_attach), | |||||
DEVMETHOD(device_detach, i2c_detach), | DEVMETHOD(device_detach, i2c_detach), | ||||
DEVMETHOD(ofw_bus_get_node, i2c_get_node), | |||||
DEVMETHOD(iicbus_callback, iicbus_null_callback), | DEVMETHOD(iicbus_callback, iicbus_null_callback), | ||||
DEVMETHOD(iicbus_repeated_start, i2c_repeated_start), | DEVMETHOD(iicbus_repeated_start, i2c_repeated_start), | ||||
DEVMETHOD(iicbus_start, i2c_start), | DEVMETHOD(iicbus_start, i2c_start), | ||||
DEVMETHOD(iicbus_stop, i2c_stop), | DEVMETHOD(iicbus_stop, i2c_stop), | ||||
DEVMETHOD(iicbus_reset, i2c_reset), | DEVMETHOD(iicbus_reset, i2c_reset), | ||||
DEVMETHOD(iicbus_read, i2c_read), | DEVMETHOD(iicbus_read, i2c_read), | ||||
DEVMETHOD(iicbus_write, i2c_write), | DEVMETHOD(iicbus_write, i2c_write), | ||||
DEVMETHOD(iicbus_transfer, iicbus_transfer_gen), | DEVMETHOD(iicbus_transfer, iicbus_transfer_gen), | ||||
{ 0, 0 } | { 0, 0 } | ||||
}; | }; | ||||
static driver_t i2c_driver = { | driver_t vf_i2c_driver = { | ||||
"i2c", | "i2c", | ||||
i2c_methods, | i2c_methods, | ||||
sizeof(struct i2c_softc), | sizeof(struct i2c_softc), | ||||
}; | }; | ||||
static devclass_t i2c_devclass; | |||||
DRIVER_MODULE(i2c, simplebus, i2c_driver, i2c_devclass, 0, 0); | |||||
DRIVER_MODULE(iicbus, i2c, iicbus_driver, iicbus_devclass, 0, 0); | |||||
DRIVER_MODULE(ofw_iicbus, i2c, ofw_iicbus_driver, ofw_iicbus_devclass, 0, 0); |