Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/gpio/gpioiic.c
/*- | /*- | ||||
* Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org> | * Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org> | ||||
* Copyright (c) 2010 Luiz Otavio O Souza | * Copyright (c) 2010 Luiz Otavio O Souza | ||||
* Copyright (c) 2017 Hiroki Mori | |||||
* All rights reserved. | * All rights reserved. | ||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
* 1. Redistributions of source code must retain the above copyright | * 1. Redistributions of source code must retain the above copyright | ||||
* notice, this list of conditions and the following disclaimer. | * notice, this list of conditions and the following disclaimer. | ||||
* 2. Redistributions in binary form must reproduce the above copyright | * 2. Redistributions in binary form must reproduce the above copyright | ||||
Show All 40 Lines | |||||
#define GPIOIIC_SCL_DFLT 0 | #define GPIOIIC_SCL_DFLT 0 | ||||
#define GPIOIIC_SDA_DFLT 1 | #define GPIOIIC_SDA_DFLT 1 | ||||
#define GPIOIIC_MIN_PINS 2 | #define GPIOIIC_MIN_PINS 2 | ||||
struct gpioiic_softc | struct gpioiic_softc | ||||
{ | { | ||||
device_t sc_dev; | device_t sc_dev; | ||||
device_t sc_busdev; | device_t sc_busdev; | ||||
#ifdef FDT | |||||
gpio_pin_t scl_pin; | |||||
gpio_pin_t sda_pin; | |||||
#else | |||||
int scl_pin; | int scl_pin; | ||||
int sda_pin; | int sda_pin; | ||||
#endif | |||||
mizhka: Is it possible to make support of SCL/SDA as "struct gpio_pin" for non-FDT case as well? | |||||
yamori813_yahoo.co.jpAuthorUnsubmitted Not Done Inline ActionsI seem other non-FDT gpio code use directly value. I think good that is not change this implement. yamori813_yahoo.co.jp: I seem other non-FDT gpio code use directly value. I think good that is not change this… | |||||
}; | }; | ||||
static int gpioiic_probe(device_t); | static int gpioiic_probe(device_t); | ||||
static int gpioiic_attach(device_t); | static int gpioiic_attach(device_t); | ||||
/* iicbb interface */ | /* iicbb interface */ | ||||
static void gpioiic_reset_bus(device_t); | static void gpioiic_reset_bus(device_t); | ||||
static void gpioiic_setsda(device_t, int); | static void gpioiic_setsda(device_t, int); | ||||
static void gpioiic_setscl(device_t, int); | static void gpioiic_setscl(device_t, int); | ||||
static int gpioiic_getsda(device_t); | static int gpioiic_getsda(device_t); | ||||
static int gpioiic_getscl(device_t); | static int gpioiic_getscl(device_t); | ||||
static int gpioiic_reset(device_t, u_char, u_char, u_char *); | static int gpioiic_reset(device_t, u_char, u_char, u_char *); | ||||
static int | static int | ||||
gpioiic_probe(device_t dev) | gpioiic_probe(device_t dev) | ||||
{ | { | ||||
struct gpiobus_ivar *devi; | |||||
#ifdef FDT | #ifdef FDT | ||||
if (!ofw_bus_status_okay(dev)) | if (!ofw_bus_status_okay(dev)) | ||||
return (ENXIO); | return (ENXIO); | ||||
if (!ofw_bus_is_compatible(dev, "gpioiic")) | if (!ofw_bus_is_compatible(dev, "gpioiic")) | ||||
return (ENXIO); | return (ENXIO); | ||||
#endif | #else | ||||
struct gpiobus_ivar *devi; | |||||
devi = GPIOBUS_IVAR(dev); | devi = GPIOBUS_IVAR(dev); | ||||
if (devi->npins < GPIOIIC_MIN_PINS) { | if (devi->npins < GPIOIIC_MIN_PINS) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"gpioiic needs at least %d GPIO pins (only %d given).\n", | "gpioiic needs at least %d GPIO pins (only %d given).\n", | ||||
GPIOIIC_MIN_PINS, devi->npins); | GPIOIIC_MIN_PINS, devi->npins); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
#endif | |||||
device_set_desc(dev, "GPIO I2C bit-banging driver"); | device_set_desc(dev, "GPIO I2C bit-banging driver"); | ||||
return (BUS_PROBE_DEFAULT); | return (BUS_PROBE_DEFAULT); | ||||
} | } | ||||
static int | static int | ||||
gpioiic_attach(device_t dev) | gpioiic_attach(device_t dev) | ||||
{ | { | ||||
device_t bitbang; | device_t bitbang; | ||||
#ifdef FDT | #ifdef FDT | ||||
phandle_t node; | phandle_t node; | ||||
pcell_t pin; | int err; | ||||
#endif | #else | ||||
struct gpiobus_ivar *devi; | struct gpiobus_ivar *devi; | ||||
#endif | |||||
struct gpioiic_softc *sc; | struct gpioiic_softc *sc; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
sc->sc_dev = dev; | sc->sc_dev = dev; | ||||
sc->sc_busdev = device_get_parent(dev); | sc->sc_busdev = device_get_parent(dev); | ||||
#ifndef FDT | |||||
if (resource_int_value(device_get_name(dev), | if (resource_int_value(device_get_name(dev), | ||||
device_get_unit(dev), "scl", &sc->scl_pin)) | device_get_unit(dev), "scl", &sc->scl_pin)) | ||||
sc->scl_pin = GPIOIIC_SCL_DFLT; | sc->scl_pin = GPIOIIC_SCL_DFLT; | ||||
if (resource_int_value(device_get_name(dev), | if (resource_int_value(device_get_name(dev), | ||||
device_get_unit(dev), "sda", &sc->sda_pin)) | device_get_unit(dev), "sda", &sc->sda_pin)) | ||||
sc->sda_pin = GPIOIIC_SDA_DFLT; | sc->sda_pin = GPIOIIC_SDA_DFLT; | ||||
#ifdef FDT | |||||
if ((node = ofw_bus_get_node(dev)) == -1) | |||||
return (ENXIO); | |||||
if (OF_getencprop(node, "scl", &pin, sizeof(pin)) > 0) | |||||
sc->scl_pin = (int)pin; | |||||
if (OF_getencprop(node, "sda", &pin, sizeof(pin)) > 0) | |||||
sc->sda_pin = (int)pin; | |||||
#endif | |||||
if (sc->scl_pin < 0 || sc->scl_pin > 1) | if (sc->scl_pin < 0 || sc->scl_pin > 1) | ||||
sc->scl_pin = GPIOIIC_SCL_DFLT; | sc->scl_pin = GPIOIIC_SCL_DFLT; | ||||
if (sc->sda_pin < 0 || sc->sda_pin > 1) | if (sc->sda_pin < 0 || sc->sda_pin > 1) | ||||
sc->sda_pin = GPIOIIC_SDA_DFLT; | sc->sda_pin = GPIOIIC_SDA_DFLT; | ||||
devi = GPIOBUS_IVAR(dev); | devi = GPIOBUS_IVAR(dev); | ||||
device_printf(dev, "SCL pin: %d, SDA pin: %d\n", | device_printf(dev, "SCL pin: %d, SDA pin: %d\n", | ||||
devi->pins[sc->scl_pin], devi->pins[sc->sda_pin]); | devi->pins[sc->scl_pin], devi->pins[sc->sda_pin]); | ||||
#else | |||||
node = ofw_bus_get_node(sc->sc_dev); | |||||
// err = gpio_pin_get_by_ofw_idx(sc->sc_dev, node, 0, &sc->scl_pin); | |||||
err = gpio_pin_get_by_ofw_name(sc->sc_dev, node, "scl", &sc->scl_pin); | |||||
if (err != 0) { | |||||
device_printf(sc->sc_dev, "cannot get pin scl\n"); | |||||
return (ENXIO); | |||||
} | |||||
// err = gpio_pin_get_by_ofw_idx(sc->sc_dev, node, 1, &sc->sda_pin); | |||||
err = gpio_pin_get_by_ofw_name(sc->sc_dev, node, "sda", &sc->sda_pin); | |||||
if (err != 0) { | |||||
device_printf(sc->sc_dev, "cannot get pin sda\n"); | |||||
return (ENXIO); | |||||
} | |||||
#endif | |||||
/* add generic bit-banging code */ | /* add generic bit-banging code */ | ||||
bitbang = device_add_child(dev, "iicbb", -1); | bitbang = device_add_child(dev, "iicbb", -1); | ||||
device_probe_and_attach(bitbang); | device_probe_and_attach(bitbang); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Reset bus by setting SDA first and then SCL. | * Reset bus by setting SDA first and then SCL. | ||||
* Must always be called with gpio bus locked. | * Must always be called with gpio bus locked. | ||||
*/ | */ | ||||
static void | static void | ||||
gpioiic_reset_bus(device_t dev) | gpioiic_reset_bus(device_t dev) | ||||
{ | { | ||||
struct gpioiic_softc *sc = device_get_softc(dev); | struct gpioiic_softc *sc; | ||||
sc = device_get_softc(dev); | |||||
#ifdef FDT | |||||
gpio_pin_setflags(sc->sda_pin, GPIO_PIN_INPUT); | |||||
gpio_pin_setflags(sc->scl_pin, GPIO_PIN_INPUT); | |||||
#else | |||||
GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sda_pin, | GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sda_pin, | ||||
GPIO_PIN_INPUT); | GPIO_PIN_INPUT); | ||||
GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->scl_pin, | GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->scl_pin, | ||||
GPIO_PIN_INPUT); | GPIO_PIN_INPUT); | ||||
#endif | |||||
} | } | ||||
static void | static void | ||||
gpioiic_setsda(device_t dev, int val) | gpioiic_setsda(device_t dev, int val) | ||||
{ | { | ||||
struct gpioiic_softc *sc = device_get_softc(dev); | struct gpioiic_softc *sc; | ||||
sc = device_get_softc(dev); | |||||
if (val == 0) { | if (val == 0) { | ||||
#ifdef FDT | |||||
gpio_pin_set_active(sc->sda_pin, 0); | |||||
gpio_pin_setflags(sc->sda_pin, GPIO_PIN_OUTPUT); | |||||
#else | |||||
GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, sc->sda_pin, 0); | GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, sc->sda_pin, 0); | ||||
GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sda_pin, | GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sda_pin, | ||||
GPIO_PIN_OUTPUT); | GPIO_PIN_OUTPUT); | ||||
#endif | |||||
} else { | } else { | ||||
#ifdef FDT | |||||
gpio_pin_set_active(sc->sda_pin, 1); | |||||
gpio_pin_setflags(sc->sda_pin, GPIO_PIN_OUTPUT); | |||||
#else | |||||
GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sda_pin, | GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sda_pin, | ||||
GPIO_PIN_INPUT); | GPIO_PIN_INPUT); | ||||
#endif | |||||
} | } | ||||
} | } | ||||
static void | static void | ||||
gpioiic_setscl(device_t dev, int val) | gpioiic_setscl(device_t dev, int val) | ||||
{ | { | ||||
struct gpioiic_softc *sc = device_get_softc(dev); | struct gpioiic_softc *sc; | ||||
sc = device_get_softc(dev); | |||||
if (val == 0) { | if (val == 0) { | ||||
#ifdef FDT | |||||
gpio_pin_set_active(sc->scl_pin, 0); | |||||
gpio_pin_setflags(sc->scl_pin, GPIO_PIN_OUTPUT); | |||||
#else | |||||
GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, sc->scl_pin, 0); | GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, sc->scl_pin, 0); | ||||
GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->scl_pin, | GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->scl_pin, | ||||
GPIO_PIN_OUTPUT); | GPIO_PIN_OUTPUT); | ||||
#endif | |||||
} else { | } else { | ||||
#ifdef FDT | |||||
gpio_pin_set_active(sc->scl_pin, 1); | |||||
gpio_pin_setflags(sc->scl_pin, GPIO_PIN_OUTPUT); | |||||
#else | |||||
GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->scl_pin, | GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->scl_pin, | ||||
GPIO_PIN_INPUT); | GPIO_PIN_INPUT); | ||||
#endif | |||||
} | } | ||||
} | } | ||||
static int | static int | ||||
gpioiic_getscl(device_t dev) | gpioiic_getscl(device_t dev) | ||||
{ | { | ||||
struct gpioiic_softc *sc = device_get_softc(dev); | struct gpioiic_softc *sc; | ||||
unsigned int val; | |||||
sc = device_get_softc(dev); | |||||
#ifdef FDT | |||||
bool val; | |||||
gpio_pin_setflags(sc->scl_pin, GPIO_PIN_INPUT); | |||||
gpio_pin_is_active(sc->scl_pin, &val); | |||||
#else | |||||
unsigned int val; | |||||
GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->scl_pin, | GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->scl_pin, | ||||
GPIO_PIN_INPUT); | GPIO_PIN_INPUT); | ||||
GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, sc->scl_pin, &val); | GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, sc->scl_pin, &val); | ||||
#endif | |||||
return ((int)val); | return ((int)val); | ||||
} | } | ||||
static int | static int | ||||
gpioiic_getsda(device_t dev) | gpioiic_getsda(device_t dev) | ||||
{ | { | ||||
struct gpioiic_softc *sc = device_get_softc(dev); | struct gpioiic_softc *sc; | ||||
unsigned int val; | |||||
sc = device_get_softc(dev); | |||||
#ifdef FDT | |||||
bool val; | |||||
gpio_pin_setflags(sc->sda_pin, GPIO_PIN_INPUT); | |||||
gpio_pin_is_active(sc->sda_pin, &val); | |||||
#else | |||||
unsigned int val; | |||||
GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sda_pin, | GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sda_pin, | ||||
GPIO_PIN_INPUT); | GPIO_PIN_INPUT); | ||||
GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, sc->sda_pin, &val); | GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, sc->sda_pin, &val); | ||||
#endif | |||||
return ((int)val); | return ((int)val); | ||||
} | } | ||||
static int | static int | ||||
gpioiic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) | gpioiic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) | ||||
{ | { | ||||
struct gpioiic_softc *sc; | struct gpioiic_softc *sc; | ||||
Show All 38 Lines | |||||
}; | }; | ||||
static driver_t gpioiic_driver = { | static driver_t gpioiic_driver = { | ||||
"gpioiic", | "gpioiic", | ||||
gpioiic_methods, | gpioiic_methods, | ||||
sizeof(struct gpioiic_softc), | sizeof(struct gpioiic_softc), | ||||
}; | }; | ||||
#ifdef FDT | |||||
DRIVER_MODULE(gpioiic, ofwbus, gpioiic_driver, gpioiic_devclass, 0, 0); | |||||
#endif | |||||
DRIVER_MODULE(gpioiic, gpiobus, gpioiic_driver, gpioiic_devclass, 0, 0); | DRIVER_MODULE(gpioiic, gpiobus, gpioiic_driver, gpioiic_devclass, 0, 0); | ||||
DRIVER_MODULE(iicbb, gpioiic, iicbb_driver, iicbb_devclass, 0, 0); | DRIVER_MODULE(iicbb, gpioiic, iicbb_driver, iicbb_devclass, 0, 0); | ||||
MODULE_DEPEND(gpioiic, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER); | MODULE_DEPEND(gpioiic, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER); | ||||
MODULE_DEPEND(gpioiic, gpiobus, 1, 1, 1); | MODULE_DEPEND(gpioiic, gpiobus, 1, 1, 1); |
Is it possible to make support of SCL/SDA as "struct gpio_pin" for non-FDT case as well?