Commit 62202f53 authored by Alessandro Rubini's avatar Alessandro Rubini

gpio.c: new subsystem

parent d57aed07
......@@ -10,7 +10,7 @@ ccflags-y += -DDEBUG # temporary
obj-m := spec-fine-delay.o
spec-fine-delay-objs = fd-zio.o fd-spec.o fd-core.o
spec-fine-delay-objs += onewire.o spi.o i2c.o
spec-fine-delay-objs += onewire.o spi.o i2c.o gpio.o
spec-fine-delay-objs += acam.o pll.o time.o
all: modules
......
......@@ -60,6 +60,7 @@ struct modlist {
#define M(x) { #x, fd_ ## x ## _init, fd_ ## x ## _exit }
static struct modlist mods[] = {
M(spi),
M(gpio),
M(pll),
//M(w1),
//M(i2c),
......
......@@ -13,6 +13,16 @@ struct spec_fd {
#define FD_CS_PLL 1 /* AD9516 PLL */
#define FD_CS_GPIO 2 /* MCP23S17 GPIO */
/* MCP23S17 register addresses (only ones which are used by the lib) */
#define FD_MCP_IODIR 0x00
#define FD_MCP_IPOL 0x01
#define FD_MCP_IOCON 0x0a
#define FD_MCP_GPIO 0x12
#define FD_MCP_OLAT 0x14
#define FD_GPIO_IN 0
#define FD_GPIO_OUT 1
/* Functions exported by fd-core.c */
extern int fd_probe(struct spec_dev *dev);
extern void fd_remove(struct spec_dev *dev);
......@@ -27,6 +37,12 @@ extern void fd_spi_exit(struct spec_fd *fd);
extern int fd_pll_init(struct spec_fd *fd);
extern void fd_pll_exit(struct spec_fd *fd);
/* Functions exported by gpio.c */
extern int fd_gpio_init(struct spec_fd *fd);
extern void fd_gpio_exit(struct spec_fd *fd);
extern void fd_gpio_dir(struct spec_fd *fd, int pin, int dir);
extern void fd_gpio_val(struct spec_fd *fd, int pin, int val);
/* Functions exported by fd-zio.c */
extern int fd_zio_register(void);
extern void fd_zio_unregister(void);
......
/*
* SPI access to fine-delay internals
*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2 as published by the Free Software Foundation or, at your
* option, any later version.
*/
#include <linux/io.h>
#include "fine-delay.h"
static int gpio_writel(struct spec_fd *fd, int val, int reg)
{
return fd_spi_xfer(fd, FD_CS_GPIO, 24,
0x4e0000 | (reg << 8) | val, NULL);
}
static int gpio_readl(struct spec_fd *fd, int reg)
{
uint32_t ret;
int err;
err = fd_spi_xfer(fd, FD_CS_GPIO, 24,
0x4f0000 | (reg << 8), &ret);
if (err < 0)
return err;
return ret & 0xff;
}
void fd_gpio_dir(struct spec_fd *fd, int mask, int dir)
{
int addr, val;
/* if mask is bits 8..15 use the next address */
addr = FD_MCP_IODIR;
if (mask & 0xff00) {
mask >>= 8;
addr++;
}
val = gpio_readl(fd, addr) & ~mask;
if (dir == FD_GPIO_IN)
val |= mask;
gpio_writel(fd, val, addr);
}
void fd_gpio_val(struct spec_fd *fd, int mask, int values)
{
int addr, reg;
/* if mask is bits 8..15 use the next address */
addr = FD_MCP_OLAT;
if (mask & 0xff00) {
mask >>= 8;
values >>= 8;
addr++;
}
reg = gpio_readl(fd, addr) & ~mask;
gpio_writel(fd, reg | values, addr);
}
int fd_gpio_init(struct spec_fd *fd)
{
int i, val;
pr_debug("%s\n",__func__);
if (gpio_writel(fd, 0x00, FD_MCP_IOCON) < 0)
goto out;
/* Try to read and write a register to test the SPI connection */
for (val = 0xaa; val >= 0; val -= 0x11) {
if (gpio_writel(fd, val, FD_MCP_IPOL) < 0)
goto out;
i = gpio_readl(fd, FD_MCP_IPOL);
if (i < 0)
goto out;
if (i != val) {
pr_err("%s: Error in GPIO communication\n",
KBUILD_MODNAME);
pr_err(" (got 0x%x, expected 0x%x)\n", i, val);
return -EIO;
}
}
/* last time we wrote 0, ok */
return 0;
out:
pr_err("%s: Error in SPI communication\n", KBUILD_MODNAME);
return -EIO;
}
void fd_gpio_exit(struct spec_fd *fd)
{
/* nothing to do */
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment