brintos

brintos / linux-shallow public Read only

0
0
Text · 3.1 KiB · 7e29a2d Raw
136 lines · c
1// SPDX-License-Identifier: GPL-2.0+2//3// Gateworks I2C PLD GPIO expander4//5// Copyright (C) 2019 Linus Walleij <linus.walleij@linaro.org>6//7// Based on code and know-how from the OpenWrt driver:8// Copyright (C) 2009 Gateworks Corporation9// Authors: Chris Lang, Imre Kaloz10 11#include <linux/bits.h>12#include <linux/kernel.h>13#include <linux/slab.h>14#include <linux/gpio/driver.h>15#include <linux/i2c.h>16#include <linux/module.h>17 18/**19 * struct gw_pld - State container for Gateworks PLD20 * @chip: GPIO chip instance21 * @client: I2C client22 * @out: shadow register for the output bute23 */24struct gw_pld {25	struct gpio_chip chip;26	struct i2c_client *client;27	u8 out;28};29 30/*31 * The Gateworks I2C PLD chip only expose one read and one write register.32 * Writing a "one" bit (to match the reset state) lets that pin be used as an33 * input. It is an open-drain model.34 */35static int gw_pld_input8(struct gpio_chip *gc, unsigned offset)36{37	struct gw_pld *gw = gpiochip_get_data(gc);38 39	gw->out |= BIT(offset);40	return i2c_smbus_write_byte(gw->client, gw->out);41}42 43static int gw_pld_get8(struct gpio_chip *gc, unsigned offset)44{45	struct gw_pld *gw = gpiochip_get_data(gc);46	s32 val;47 48	val = i2c_smbus_read_byte(gw->client);49 50	return (val < 0) ? 0 : !!(val & BIT(offset));51}52 53static int gw_pld_output8(struct gpio_chip *gc, unsigned offset, int value)54{55	struct gw_pld *gw = gpiochip_get_data(gc);56 57	if (value)58		gw->out |= BIT(offset);59	else60		gw->out &= ~BIT(offset);61 62	return i2c_smbus_write_byte(gw->client, gw->out);63}64 65static void gw_pld_set8(struct gpio_chip *gc, unsigned offset, int value)66{67	gw_pld_output8(gc, offset, value);68}69 70static int gw_pld_probe(struct i2c_client *client)71{72	struct device *dev = &client->dev;73	struct gw_pld *gw;74	int ret;75 76	gw = devm_kzalloc(dev, sizeof(*gw), GFP_KERNEL);77	if (!gw)78		return -ENOMEM;79 80	gw->chip.base = -1;81	gw->chip.can_sleep = true;82	gw->chip.parent = dev;83	gw->chip.owner = THIS_MODULE;84	gw->chip.label = dev_name(dev);85	gw->chip.ngpio = 8;86	gw->chip.direction_input = gw_pld_input8;87	gw->chip.get = gw_pld_get8;88	gw->chip.direction_output = gw_pld_output8;89	gw->chip.set = gw_pld_set8;90	gw->client = client;91 92	/*93	 * The Gateworks I2C PLD chip does not properly send the acknowledge94	 * bit at all times, but we can still use the standard i2c_smbus95	 * functions by simply ignoring this bit.96	 */97	client->flags |= I2C_M_IGNORE_NAK;98	gw->out = 0xFF;99 100	i2c_set_clientdata(client, gw);101 102	ret = devm_gpiochip_add_data(dev, &gw->chip, gw);103	if (ret)104		return ret;105 106	dev_info(dev, "registered Gateworks PLD GPIO device\n");107 108	return 0;109}110 111static const struct i2c_device_id gw_pld_id[] = {112	{ "gw-pld", },113	{ }114};115MODULE_DEVICE_TABLE(i2c, gw_pld_id);116 117static const struct of_device_id gw_pld_dt_ids[] = {118	{ .compatible = "gateworks,pld-gpio", },119	{ },120};121MODULE_DEVICE_TABLE(of, gw_pld_dt_ids);122 123static struct i2c_driver gw_pld_driver = {124	.driver = {125		.name = "gw_pld",126		.of_match_table = gw_pld_dt_ids,127	},128	.probe = gw_pld_probe,129	.id_table = gw_pld_id,130};131module_i2c_driver(gw_pld_driver);132 133MODULE_DESCRIPTION("Gateworks I2C PLD GPIO expander");134MODULE_LICENSE("GPL");135MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");136