uboot/drivers/gpio/pca9698.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2011
   4 * Dirk Eibach,  Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
   5 */
   6
   7/*
   8 * Driver for NXP's pca9698 40 bit I2C gpio expander
   9 */
  10
  11#include <common.h>
  12#include <i2c.h>
  13#include <linux/errno.h>
  14#include <pca9698.h>
  15
  16/*
  17 * The pca9698 registers
  18 */
  19
  20#define PCA9698_REG_INPUT               0x00
  21#define PCA9698_REG_OUTPUT              0x08
  22#define PCA9698_REG_POLARITY            0x10
  23#define PCA9698_REG_CONFIG              0x18
  24
  25#define PCA9698_BUFFER_SIZE             5
  26#define PCA9698_GPIO_COUNT              40
  27
  28static int pca9698_read40(u8 addr, u8 offset, u8 *buffer)
  29{
  30        u8 command = offset | 0x80;  /* autoincrement */
  31
  32        return i2c_read(addr, command, 1, buffer, PCA9698_BUFFER_SIZE);
  33}
  34
  35static int pca9698_write40(u8 addr, u8 offset, u8 *buffer)
  36{
  37        u8 command = offset | 0x80;  /* autoincrement */
  38
  39        return i2c_write(addr, command, 1, buffer, PCA9698_BUFFER_SIZE);
  40}
  41
  42static void pca9698_set_bit(unsigned gpio, u8 *buffer, unsigned value)
  43{
  44        unsigned byte = gpio / 8;
  45        unsigned bit = gpio % 8;
  46
  47        if (value)
  48                buffer[byte] |= (1 << bit);
  49        else
  50                buffer[byte] &= ~(1 << bit);
  51}
  52
  53int pca9698_request(unsigned gpio, const char *label)
  54{
  55        if (gpio >= PCA9698_GPIO_COUNT)
  56                return -EINVAL;
  57
  58        return 0;
  59}
  60
  61void pca9698_free(unsigned gpio)
  62{
  63}
  64
  65int pca9698_direction_input(u8 addr, unsigned gpio)
  66{
  67        u8 data[PCA9698_BUFFER_SIZE];
  68        int res;
  69
  70        res = pca9698_read40(addr, PCA9698_REG_CONFIG, data);
  71        if (res)
  72                return res;
  73
  74        pca9698_set_bit(gpio, data, 1);
  75
  76        return pca9698_write40(addr, PCA9698_REG_CONFIG, data);
  77}
  78
  79int pca9698_direction_output(u8 addr, unsigned gpio, int value)
  80{
  81        u8 data[PCA9698_BUFFER_SIZE];
  82        int res;
  83
  84        res = pca9698_set_value(addr, gpio, value);
  85        if (res)
  86                return res;
  87
  88        res = pca9698_read40(addr, PCA9698_REG_CONFIG, data);
  89        if (res)
  90                return res;
  91
  92        pca9698_set_bit(gpio, data, 0);
  93
  94        return pca9698_write40(addr, PCA9698_REG_CONFIG, data);
  95}
  96
  97int pca9698_get_value(u8 addr, unsigned gpio)
  98{
  99        unsigned config_byte = gpio / 8;
 100        unsigned config_bit = gpio % 8;
 101        unsigned value;
 102        u8 data[PCA9698_BUFFER_SIZE];
 103        int res;
 104
 105        res = pca9698_read40(addr, PCA9698_REG_INPUT, data);
 106        if (res)
 107                return -1;
 108
 109        value = data[config_byte] & (1 << config_bit);
 110
 111        return !!value;
 112}
 113
 114int pca9698_set_value(u8 addr, unsigned gpio, int value)
 115{
 116        u8 data[PCA9698_BUFFER_SIZE];
 117        int res;
 118
 119        res = pca9698_read40(addr, PCA9698_REG_OUTPUT, data);
 120        if (res)
 121                return res;
 122
 123        pca9698_set_bit(gpio, data, value);
 124
 125        return pca9698_write40(addr, PCA9698_REG_OUTPUT, data);
 126}
 127