summaryrefslogtreecommitdiff
path: root/usr/src/uts/sun4u/io/gpio_87317.c
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/uts/sun4u/io/gpio_87317.c
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/uts/sun4u/io/gpio_87317.c')
-rw-r--r--usr/src/uts/sun4u/io/gpio_87317.c433
1 files changed, 433 insertions, 0 deletions
diff --git a/usr/src/uts/sun4u/io/gpio_87317.c b/usr/src/uts/sun4u/io/gpio_87317.c
new file mode 100644
index 0000000000..b784b83d8d
--- /dev/null
+++ b/usr/src/uts/sun4u/io/gpio_87317.c
@@ -0,0 +1,433 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+#include <sys/cmn_err.h>
+#include <sys/param.h>
+#include <sys/modctl.h>
+#include <sys/conf.h>
+#include <sys/open.h>
+#include <sys/stat.h>
+#include <sys/clock.h>
+#include <sys/gpio_87317.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/file.h>
+#ifdef DEBUG
+#include <sys/promif.h>
+#endif
+
+
+/* a non zero value causes debug info to be displayed */
+uint_t gpio_debug_flag = 0;
+
+
+#ifdef DEBUG
+static void gpio_debug(dev_info_t *dip, char *format, uint_t arg1, uint_t arg2,
+ uint_t arg3, uint_t arg4, uint_t arg5);
+
+#define DBG(dip, format, arg1, arg2, arg3, arg4, arg5) \
+ gpio_debug(dip, format, (uint_t)arg1, (uint_t)arg2, (uint_t)arg3, \
+ (uint_t)arg4, (uint_t)arg5)
+#else
+#define DBG(dip, format, arg1, arg2, arg3, arg4, arg5)
+#endif
+
+
+/* Driver soft state structure */
+struct gpio_softc {
+ dev_info_t *gp_dip;
+ kmutex_t gp_mutex;
+ int gp_state;
+ ddi_acc_handle_t gp_handle;
+ uint8_t *gp_regs;
+};
+
+#define getsoftc(minor) \
+ ((struct gpio_softc *)ddi_get_soft_state(statep, (minor)))
+
+/* dev_ops and cb_ops entry point function declarations */
+static int gpio_attach(dev_info_t *, ddi_attach_cmd_t);
+static int gpio_detach(dev_info_t *, ddi_detach_cmd_t);
+static int gpio_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
+static int gpio_open(dev_t *, int, int, cred_t *);
+static int gpio_close(dev_t, int, int, cred_t *);
+static int gpio_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
+
+struct cb_ops gpio_cb_ops = {
+ gpio_open,
+ gpio_close,
+ nodev,
+ nodev,
+ nodev, /* dump */
+ nodev,
+ nodev,
+ gpio_ioctl,
+ nodev, /* devmap */
+ nodev,
+ nodev,
+ nochpoll,
+ ddi_prop_op,
+ NULL, /* for STREAMS drivers */
+ D_NEW | D_MP, /* driver compatibility flag */
+ CB_REV,
+ nodev,
+ nodev
+};
+
+static struct dev_ops gpio_dev_ops = {
+ DEVO_REV, /* driver build version */
+ 0, /* device reference count */
+ gpio_getinfo,
+ nulldev,
+ nulldev, /* probe */
+ gpio_attach,
+ gpio_detach,
+ nulldev, /* reset */
+ &gpio_cb_ops,
+ (struct bus_ops *)NULL,
+ nulldev /* power */
+};
+
+/* module configuration stuff */
+static void *statep;
+extern struct mod_ops mod_driverops;
+static struct modldrv modldrv = {
+ &mod_driverops,
+ "gpio driver 1.0",
+ &gpio_dev_ops
+};
+static struct modlinkage modlinkage = {
+ MODREV_1,
+ &modldrv,
+ 0
+};
+
+
+int
+_init(void)
+{
+ int e;
+
+ if (e = ddi_soft_state_init(&statep, sizeof (struct gpio_softc), 1)) {
+ return (e);
+ }
+ if ((e = mod_install(&modlinkage)) != 0) {
+ ddi_soft_state_fini(&statep);
+ }
+
+ return (e);
+}
+
+
+int
+_fini(void)
+{
+ int e;
+
+ if ((e = mod_remove(&modlinkage)) != 0) {
+ return (e);
+ }
+ ddi_soft_state_fini(&statep);
+
+ return (DDI_SUCCESS);
+}
+
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
+
+/* ARGSUSED */
+static int
+gpio_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
+{
+ int instance = getminor((dev_t)arg);
+ int retval = DDI_SUCCESS;
+ struct gpio_softc *softc;
+
+ switch (cmd) {
+ case DDI_INFO_DEVT2DEVINFO:
+ if ((softc = getsoftc(instance)) == NULL) {
+ *result = (void *)NULL;
+ retval = DDI_FAILURE;
+ } else
+ *result = (void *)softc->gp_dip;
+ break;
+
+ case DDI_INFO_DEVT2INSTANCE:
+ *result = (void *)instance;
+ break;
+
+ default:
+ retval = DDI_FAILURE;
+ }
+
+ return (retval);
+}
+
+
+static int
+gpio_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+
+ int instance;
+ struct gpio_softc *softc = NULL;
+ ddi_device_acc_attr_t dev_attr;
+
+ switch (cmd) {
+
+ case DDI_ATTACH:
+
+ /* Allocate and get the soft state structure for this instance. */
+
+ instance = ddi_get_instance(dip);
+ DBG(dip, "attach: instance is %d", instance, 0, 0, 0, 0);
+ if (ddi_soft_state_zalloc(statep, instance) != DDI_SUCCESS)
+ goto attach_failed;
+ softc = getsoftc(instance);
+ softc->gp_dip = dip;
+ softc->gp_state = 0;
+ mutex_init(&softc->gp_mutex, NULL, MUTEX_DRIVER, NULL);
+
+ /* Map in the gpio device registers. */
+
+ dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
+ dev_attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
+ dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
+ if (ddi_regs_map_setup(dip, 0, (caddr_t *)&softc->gp_regs, 0, 0,
+ &dev_attr, &softc->gp_handle) != DDI_SUCCESS)
+ goto attach_failed;
+ DBG(dip, "attach: regs=0x%x", softc->gp_regs, 0, 0, 0, 0);
+ DBG(dip, "attach: port 1 data is %x",
+ ddi_get8(softc->gp_handle, &softc->gp_regs[0]), 0, 0, 0, 0);
+ DBG(dip, "attach: port 1 direction is %x",
+ ddi_get8(softc->gp_handle, &softc->gp_regs[1]), 0, 0, 0, 0);
+ DBG(dip, "attach: port 1 output type is %x",
+ ddi_get8(softc->gp_handle, &softc->gp_regs[2]), 0, 0, 0, 0);
+ DBG(dip, "attach: port 1 pull up control type is %x",
+ ddi_get8(softc->gp_handle, &softc->gp_regs[3]), 0, 0, 0, 0);
+ DBG(dip, "attach: port 2 data is %x",
+ ddi_get8(softc->gp_handle, &softc->gp_regs[4]), 0, 0, 0, 0);
+ DBG(dip, "attach: port 2 direction is %x",
+ ddi_get8(softc->gp_handle, &softc->gp_regs[5]), 0, 0, 0, 0);
+ DBG(dip, "attach: port 2 output type is %x",
+ ddi_get8(softc->gp_handle, &softc->gp_regs[6]), 0, 0, 0, 0);
+ DBG(dip, "attach: port 2 pull up control type is %x",
+ ddi_get8(softc->gp_handle, &softc->gp_regs[7]), 0, 0, 0, 0);
+
+ /* Create device minor nodes. */
+
+ if (ddi_create_minor_node(dip, "gpio", S_IFCHR,
+ instance, NULL, NULL) == DDI_FAILURE) {
+ ddi_regs_map_free(&softc->gp_handle);
+ goto attach_failed;
+ }
+
+ ddi_report_dev(dip);
+ return (DDI_SUCCESS);
+
+ case DDI_RESUME:
+
+ /* Nothing to do for a resume. */
+
+ return (DDI_SUCCESS);
+
+ default:
+ return (DDI_FAILURE);
+ }
+
+attach_failed:
+ if (softc) {
+ mutex_destroy(&softc->gp_mutex);
+ if (softc->gp_handle)
+ ddi_regs_map_free(&softc->gp_handle);
+ ddi_soft_state_free(statep, instance);
+ ddi_remove_minor_node(dip, NULL);
+ }
+ return (DDI_FAILURE);
+}
+
+
+static int
+gpio_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+ int instance;
+ struct gpio_softc *softc;
+
+ switch (cmd) {
+ case DDI_DETACH:
+ instance = ddi_get_instance(dip);
+ DBG(dip, "detach: instance is %d", instance, 0, 0, 0, 0);
+ if ((softc = getsoftc(instance)) == NULL)
+ return (ENXIO);
+ mutex_destroy(&softc->gp_mutex);
+ ddi_regs_map_free(&softc->gp_handle);
+ ddi_soft_state_free(statep, instance);
+ ddi_remove_minor_node(dip, NULL);
+ return (DDI_SUCCESS);
+
+ case DDI_SUSPEND:
+ /* Nothing to do in the suspend case. */
+ return (DDI_SUCCESS);
+
+ default:
+ return (DDI_FAILURE);
+ }
+}
+
+
+/* ARGSUSED */
+static int
+gpio_open(dev_t *devp, int flag, int otyp, cred_t *credp)
+{
+ int instance = getminor(*devp);
+
+ DBG(NULL, "open: instance is %d", instance, 0, 0, 0, 0);
+ return (getsoftc(instance) == NULL ? ENXIO : 0);
+}
+
+
+/* ARGSUSED */
+static int
+gpio_close(dev_t dev, int flag, int otyp, cred_t *credp)
+{
+ int instance = getminor(dev);
+
+ DBG(NULL, "close: instance is %d", instance, 0, 0, 0, 0);
+ return (getsoftc(instance) == NULL ? ENXIO : 0);
+}
+
+
+/* ARGSUSED */
+static int
+gpio_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
+ int *rvalp)
+{
+ int instance = getminor(dev);
+ struct gpio_softc *softc = getsoftc(instance);
+ gpio_87317_op_t info;
+ uint8_t byte;
+
+ DBG(softc->gp_dip, "ioctl: instance is %d", instance, 0, 0, 0, 0);
+
+ if (softc == NULL)
+ return (ENXIO);
+
+ /* Copy the command from user space. */
+ if (ddi_copyin((caddr_t)arg, (caddr_t)&info, sizeof (gpio_87317_op_t),
+ mode) != 0)
+ return (EFAULT);
+
+ /* Check the command arguments. We only support port 1 in bank 0. */
+ if ((info.gpio_bank != 0) ||
+ (info.gpio_offset != GPIO_87317_PORT1_DATA)) {
+ return (EINVAL);
+ }
+
+ /* Grap the instance's mutex to insure exclusive access. */
+ mutex_enter(&softc->gp_mutex);
+
+ /* Get the contents of the GPIO register we're suppose to modify. */
+ byte = ddi_get8(softc->gp_handle, &softc->gp_regs[info.gpio_offset]);
+
+ switch (cmd) {
+ case GPIO_CMD_SET_BITS:
+ DBG(softc->gp_dip, "ioctl: SET_BITS, byte is %x", byte, 0, 0,
+ 0, 0);
+ byte |= info.gpio_data;
+ ddi_put8(softc->gp_handle, &softc->gp_regs[info.gpio_offset],
+ byte);
+ byte = ddi_get8(softc->gp_handle,
+ &softc->gp_regs[info.gpio_offset]);
+ DBG(softc->gp_dip, "ioctl: SET_BITS, byte is %x", byte, 0, 0,
+ 0, 0);
+ break;
+
+ case GPIO_CMD_CLR_BITS:
+ DBG(softc->gp_dip, "ioctl: CLR_BITS, byte is %x", byte, 0, 0,
+ 0, 0);
+ byte &= ~info.gpio_data;
+ ddi_put8(softc->gp_handle, &softc->gp_regs[info.gpio_offset],
+ byte);
+ byte = ddi_get8(softc->gp_handle,
+ &softc->gp_regs[info.gpio_offset]);
+ DBG(softc->gp_dip, "ioctl: CLR_BITS, byte is %x", byte, 0, 0,
+ 0, 0);
+ break;
+
+ case GPIO_CMD_GET:
+ DBG(softc->gp_dip, "ioctl: GPIO_CMD_GET", 0, 0, 0, 0, 0);
+ info.gpio_data = byte;
+ if (ddi_copyout((caddr_t)&info, (caddr_t)arg,
+ sizeof (gpio_87317_op_t), mode) != 0) {
+ mutex_exit(&softc->gp_mutex);
+ return (EFAULT);
+ }
+ break;
+
+ case GPIO_CMD_SET:
+ DBG(softc->gp_dip, "ioctl: GPIO_CMD_SET", 0, 0, 0, 0, 0);
+ ddi_put8(softc->gp_handle, &softc->gp_regs[info.gpio_offset],
+ info.gpio_data);
+ break;
+
+ default:
+ mutex_exit(&softc->gp_mutex);
+ return (EINVAL);
+ }
+
+ mutex_exit(&softc->gp_mutex);
+ return (0);
+}
+
+
+#ifdef DEBUG
+void
+gpio_debug(dev_info_t *dip, char *format, uint_t arg1, uint_t arg2, uint_t arg3,
+ uint_t arg4, uint_t arg5)
+{
+ if (gpio_debug_flag == 0) {
+ return;
+ }
+
+ if (dip == NULL) {
+ prom_printf("gpio: ");
+ } else {
+ prom_printf("%s%d: ", ddi_driver_name(dip),
+ ddi_get_instance(dip));
+ }
+ prom_printf(format, arg1, arg2, arg3, arg4, arg5);
+ prom_printf("\n");
+}
+#endif