linux/drivers/gpio/gpio-mc9s08dz60.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright 2009-2012 Freescale Semiconductor, Inc. All Rights Reserved.
   4 *
   5 * Author: Wu Guoxing <b39297@freescale.com>
   6 */
   7
   8#include <linux/kernel.h>
   9#include <linux/init.h>
  10#include <linux/slab.h>
  11#include <linux/i2c.h>
  12#include <linux/gpio/driver.h>
  13
  14#define GPIO_GROUP_NUM 2
  15#define GPIO_NUM_PER_GROUP 8
  16#define GPIO_NUM (GPIO_GROUP_NUM*GPIO_NUM_PER_GROUP)
  17
  18struct mc9s08dz60 {
  19        struct i2c_client *client;
  20        struct gpio_chip chip;
  21};
  22
  23static void mc9s_gpio_to_reg_and_bit(int offset, u8 *reg, u8 *bit)
  24{
  25        *reg = 0x20 + offset / GPIO_NUM_PER_GROUP;
  26        *bit = offset % GPIO_NUM_PER_GROUP;
  27}
  28
  29static int mc9s08dz60_get_value(struct gpio_chip *gc, unsigned offset)
  30{
  31        u8 reg, bit;
  32        s32 value;
  33        struct mc9s08dz60 *mc9s = gpiochip_get_data(gc);
  34
  35        mc9s_gpio_to_reg_and_bit(offset, &reg, &bit);
  36        value = i2c_smbus_read_byte_data(mc9s->client, reg);
  37
  38        return (value >= 0) ? (value >> bit) & 0x1 : 0;
  39}
  40
  41static int mc9s08dz60_set(struct mc9s08dz60 *mc9s, unsigned offset, int val)
  42{
  43        u8 reg, bit;
  44        s32 value;
  45
  46        mc9s_gpio_to_reg_and_bit(offset, &reg, &bit);
  47        value = i2c_smbus_read_byte_data(mc9s->client, reg);
  48        if (value >= 0) {
  49                if (val)
  50                        value |= 1 << bit;
  51                else
  52                        value &= ~(1 << bit);
  53
  54                return i2c_smbus_write_byte_data(mc9s->client, reg, value);
  55        } else
  56                return value;
  57
  58}
  59
  60
  61static void mc9s08dz60_set_value(struct gpio_chip *gc, unsigned offset, int val)
  62{
  63        struct mc9s08dz60 *mc9s = gpiochip_get_data(gc);
  64
  65        mc9s08dz60_set(mc9s, offset, val);
  66}
  67
  68static int mc9s08dz60_direction_output(struct gpio_chip *gc,
  69                                       unsigned offset, int val)
  70{
  71        struct mc9s08dz60 *mc9s = gpiochip_get_data(gc);
  72
  73        return mc9s08dz60_set(mc9s, offset, val);
  74}
  75
  76static int mc9s08dz60_probe(struct i2c_client *client,
  77                            const struct i2c_device_id *id)
  78{
  79        struct mc9s08dz60 *mc9s;
  80
  81        mc9s = devm_kzalloc(&client->dev, sizeof(*mc9s), GFP_KERNEL);
  82        if (!mc9s)
  83                return -ENOMEM;
  84
  85        mc9s->chip.label = client->name;
  86        mc9s->chip.base = -1;
  87        mc9s->chip.parent = &client->dev;
  88        mc9s->chip.owner = THIS_MODULE;
  89        mc9s->chip.ngpio = GPIO_NUM;
  90        mc9s->chip.can_sleep = true;
  91        mc9s->chip.get = mc9s08dz60_get_value;
  92        mc9s->chip.set = mc9s08dz60_set_value;
  93        mc9s->chip.direction_output = mc9s08dz60_direction_output;
  94        mc9s->client = client;
  95        i2c_set_clientdata(client, mc9s);
  96
  97        return devm_gpiochip_add_data(&client->dev, &mc9s->chip, mc9s);
  98}
  99
 100static const struct i2c_device_id mc9s08dz60_id[] = {
 101        {"mc9s08dz60", 0},
 102        {},
 103};
 104
 105static struct i2c_driver mc9s08dz60_i2c_driver = {
 106        .driver = {
 107                .name = "mc9s08dz60",
 108        },
 109        .probe = mc9s08dz60_probe,
 110        .id_table = mc9s08dz60_id,
 111};
 112builtin_i2c_driver(mc9s08dz60_i2c_driver);
 113