1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * max7320 I2C GPIO EXPANDER DRIVER
4  *
5  * Copyright (C) 2021 Hannes Schmelzer <oe5hpm@oevsv.at>
6  * B&R Industrial Automation GmbH - http://www.br-automation.com
7  *
8  */
9 
10 #include <common.h>
11 #include <dm.h>
12 #include <i2c.h>
13 #include <asm-generic/gpio.h>
14 #include <linux/bitops.h>
15 
16 struct max7320_chip {
17 	u32 outreg;
18 };
19 
max7320_direction_output(struct udevice * dev,unsigned int offset,int value)20 static int max7320_direction_output(struct udevice *dev,
21 				    unsigned int offset, int value)
22 {
23 	struct max7320_chip *plat = dev_get_plat(dev);
24 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
25 	struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
26 
27 	int ret;
28 
29 	if (value)
30 		plat->outreg |= BIT(offset);
31 	else
32 		plat->outreg &= ~BIT(offset);
33 
34 	ret = dm_i2c_write(dev,
35 			   plat->outreg & 0xff,
36 			   (uint8_t *)&plat->outreg + 1,
37 			   uc_priv->gpio_count > 8 ? 1 : 0);
38 	if (ret)
39 		printf("%s i2c write failed to addr %x\n", __func__,
40 		       chip->chip_addr);
41 
42 	return ret;
43 }
44 
max7320_get_value(struct udevice * dev,unsigned int offset)45 static int max7320_get_value(struct udevice *dev, unsigned int offset)
46 {
47 	struct max7320_chip *plat = dev_get_plat(dev);
48 
49 	return (plat->outreg >> offset) & 0x1;
50 }
51 
max7320_set_value(struct udevice * dev,unsigned int offset,int value)52 static int max7320_set_value(struct udevice *dev, unsigned int offset,
53 			     int value)
54 {
55 	return max7320_direction_output(dev, offset, value);
56 }
57 
max7320_get_function(struct udevice * dev,unsigned int offset)58 static int max7320_get_function(struct udevice *dev, unsigned int offset)
59 {
60 	return GPIOF_OUTPUT;
61 }
62 
max7320_ofdata_plat(struct udevice * dev)63 static int max7320_ofdata_plat(struct udevice *dev)
64 {
65 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
66 
67 	uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios", 8);
68 	if (uc_priv->gpio_count > 16) {
69 		printf("%s: max7320 doesn't support more than 16 gpios!",
70 		       __func__);
71 		return -EINVAL;
72 	}
73 
74 	uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
75 					 "gpio-bank-name", NULL);
76 	if (!uc_priv->bank_name)
77 		uc_priv->bank_name = fdt_get_name(gd->fdt_blob,
78 						  dev_of_offset(dev), NULL);
79 
80 	return 0;
81 }
82 
max7320_gpio_probe(struct udevice * dev)83 static int max7320_gpio_probe(struct udevice  *dev)
84 {
85 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
86 
87 	debug("%s GPIO controller with %d gpios probed\n",
88 	      uc_priv->bank_name, uc_priv->gpio_count);
89 
90 	return 0;
91 }
92 
93 static const struct dm_gpio_ops max7320_gpio_ops = {
94 	.direction_output	= max7320_direction_output,
95 	.set_value		= max7320_set_value,
96 	.get_value		= max7320_get_value,
97 	.get_function		= max7320_get_function,
98 };
99 
100 static const struct udevice_id max7320_gpio_ids[] = {
101 	{ .compatible = "maxim,max7320" },
102 	{ }
103 };
104 
105 U_BOOT_DRIVER(gpio_max7320) = {
106 	.name		= "gpio_max7320",
107 	.id		= UCLASS_GPIO,
108 	.ops		= &max7320_gpio_ops,
109 	.of_match	= max7320_gpio_ids,
110 	.of_to_plat	= max7320_ofdata_plat,
111 	.probe		= max7320_gpio_probe,
112 	.plat_auto	= sizeof(struct max7320_chip),
113 };
114