xref: /rk3399_rockchip-uboot/drivers/gpio/intel_broadwell_gpio.c (revision 21342d4aed6c77a4aa7a5b2579b3c23e21aea31a)
164b17977SSimon Glass /*
264b17977SSimon Glass  * Copyright (c) 2012 The Chromium OS Authors.
364b17977SSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
464b17977SSimon Glass  */
564b17977SSimon Glass 
664b17977SSimon Glass #include <common.h>
764b17977SSimon Glass #include <dm.h>
864b17977SSimon Glass #include <errno.h>
964b17977SSimon Glass #include <fdtdec.h>
1064b17977SSimon Glass #include <pch.h>
1164b17977SSimon Glass #include <pci.h>
1226f50fbeSSimon Glass #include <syscon.h>
1364b17977SSimon Glass #include <asm/cpu.h>
1464b17977SSimon Glass #include <asm/gpio.h>
1564b17977SSimon Glass #include <asm/io.h>
1664b17977SSimon Glass #include <asm/pci.h>
1764b17977SSimon Glass #include <asm/arch/gpio.h>
1864b17977SSimon Glass #include <dt-bindings/gpio/x86-gpio.h>
1964b17977SSimon Glass 
2064b17977SSimon Glass DECLARE_GLOBAL_DATA_PTR;
2164b17977SSimon Glass 
2264b17977SSimon Glass /**
2364b17977SSimon Glass  * struct broadwell_bank_priv - Private driver data
2464b17977SSimon Glass  *
2564b17977SSimon Glass  * @regs:	Pointer to GPIO registers
2664b17977SSimon Glass  * @bank:	Bank number for this bank (0, 1 or 2)
2764b17977SSimon Glass  * @offset:	GPIO offset for this bank (0, 32 or 64)
2864b17977SSimon Glass  */
2964b17977SSimon Glass struct broadwell_bank_priv {
3064b17977SSimon Glass 	struct pch_lp_gpio_regs *regs;
3164b17977SSimon Glass 	int bank;
3264b17977SSimon Glass 	int offset;
3364b17977SSimon Glass };
3464b17977SSimon Glass 
broadwell_gpio_request(struct udevice * dev,unsigned offset,const char * label)3564b17977SSimon Glass static int broadwell_gpio_request(struct udevice *dev, unsigned offset,
3664b17977SSimon Glass 			     const char *label)
3764b17977SSimon Glass {
3864b17977SSimon Glass 	struct broadwell_bank_priv *priv = dev_get_priv(dev);
3964b17977SSimon Glass 	struct pch_lp_gpio_regs *regs = priv->regs;
4064b17977SSimon Glass 	u32 val;
4164b17977SSimon Glass 
4264b17977SSimon Glass 	/*
4364b17977SSimon Glass 	 * Make sure that the GPIO pin we want isn't already in use for some
4464b17977SSimon Glass 	 * built-in hardware function. We have to check this for every
4564b17977SSimon Glass 	 * requested pin.
4664b17977SSimon Glass 	 */
4764b17977SSimon Glass 	debug("%s: request bank %d offset %d: ", __func__, priv->bank, offset);
4864b17977SSimon Glass 	val = inl(&regs->own[priv->bank]);
4964b17977SSimon Glass 	if (!(val & (1UL << offset))) {
5064b17977SSimon Glass 		debug("gpio is reserved for internal use\n");
5164b17977SSimon Glass 		return -EPERM;
5264b17977SSimon Glass 	}
5364b17977SSimon Glass 	debug("ok\n");
5464b17977SSimon Glass 
5564b17977SSimon Glass 	return 0;
5664b17977SSimon Glass }
5764b17977SSimon Glass 
broadwell_gpio_direction_input(struct udevice * dev,unsigned offset)5864b17977SSimon Glass static int broadwell_gpio_direction_input(struct udevice *dev, unsigned offset)
5964b17977SSimon Glass {
6064b17977SSimon Glass 	struct broadwell_bank_priv *priv = dev_get_priv(dev);
6164b17977SSimon Glass 	struct pch_lp_gpio_regs *regs = priv->regs;
6264b17977SSimon Glass 
6364b17977SSimon Glass 	setio_32(&regs->config[priv->offset + offset], CONFA_DIR_INPUT);
6464b17977SSimon Glass 
6564b17977SSimon Glass 	return 0;
6664b17977SSimon Glass }
6764b17977SSimon Glass 
broadwell_gpio_get_value(struct udevice * dev,unsigned offset)6864b17977SSimon Glass static int broadwell_gpio_get_value(struct udevice *dev, unsigned offset)
6964b17977SSimon Glass {
7064b17977SSimon Glass 	struct broadwell_bank_priv *priv = dev_get_priv(dev);
7164b17977SSimon Glass 	struct pch_lp_gpio_regs *regs = priv->regs;
7264b17977SSimon Glass 
7364b17977SSimon Glass 	return inl(&regs->config[priv->offset + offset]) & CONFA_LEVEL_HIGH ?
7464b17977SSimon Glass 		1 : 0;
7564b17977SSimon Glass }
7664b17977SSimon Glass 
broadwell_gpio_set_value(struct udevice * dev,unsigned offset,int value)7764b17977SSimon Glass static int broadwell_gpio_set_value(struct udevice *dev, unsigned offset,
7864b17977SSimon Glass 				    int value)
7964b17977SSimon Glass {
8064b17977SSimon Glass 	struct broadwell_bank_priv *priv = dev_get_priv(dev);
8164b17977SSimon Glass 	struct pch_lp_gpio_regs *regs = priv->regs;
8264b17977SSimon Glass 
8364b17977SSimon Glass 	debug("%s: dev=%s, offset=%d, value=%d\n", __func__, dev->name, offset,
8464b17977SSimon Glass 	      value);
8564b17977SSimon Glass 	clrsetio_32(&regs->config[priv->offset + offset], CONFA_OUTPUT_HIGH,
8664b17977SSimon Glass 		      value ? CONFA_OUTPUT_HIGH : 0);
8764b17977SSimon Glass 
8864b17977SSimon Glass 	return 0;
8964b17977SSimon Glass }
9064b17977SSimon Glass 
broadwell_gpio_direction_output(struct udevice * dev,unsigned offset,int value)9164b17977SSimon Glass static int broadwell_gpio_direction_output(struct udevice *dev, unsigned offset,
9264b17977SSimon Glass 					   int value)
9364b17977SSimon Glass {
9464b17977SSimon Glass 	struct broadwell_bank_priv *priv = dev_get_priv(dev);
9564b17977SSimon Glass 	struct pch_lp_gpio_regs *regs = priv->regs;
9664b17977SSimon Glass 
9764b17977SSimon Glass 	broadwell_gpio_set_value(dev, offset, value);
9864b17977SSimon Glass 	clrio_32(&regs->config[priv->offset + offset], CONFA_DIR_INPUT);
9964b17977SSimon Glass 
10064b17977SSimon Glass 	return 0;
10164b17977SSimon Glass }
10264b17977SSimon Glass 
broadwell_gpio_get_function(struct udevice * dev,unsigned offset)10364b17977SSimon Glass static int broadwell_gpio_get_function(struct udevice *dev, unsigned offset)
10464b17977SSimon Glass {
10564b17977SSimon Glass 	struct broadwell_bank_priv *priv = dev_get_priv(dev);
10664b17977SSimon Glass 	struct pch_lp_gpio_regs *regs = priv->regs;
10764b17977SSimon Glass 	u32 mask = 1UL << offset;
10864b17977SSimon Glass 
10964b17977SSimon Glass 	if (!(inl(&regs->own[priv->bank]) & mask))
11064b17977SSimon Glass 		return GPIOF_FUNC;
11164b17977SSimon Glass 	if (inl(&regs->config[priv->offset + offset]) & CONFA_DIR_INPUT)
11264b17977SSimon Glass 		return GPIOF_INPUT;
11364b17977SSimon Glass 	else
11464b17977SSimon Glass 		return GPIOF_OUTPUT;
11564b17977SSimon Glass }
11664b17977SSimon Glass 
broadwell_gpio_probe(struct udevice * dev)11764b17977SSimon Glass static int broadwell_gpio_probe(struct udevice *dev)
11864b17977SSimon Glass {
11964b17977SSimon Glass 	struct broadwell_bank_platdata *plat = dev_get_platdata(dev);
12064b17977SSimon Glass 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
12164b17977SSimon Glass 	struct broadwell_bank_priv *priv = dev_get_priv(dev);
12226f50fbeSSimon Glass 	struct udevice *pinctrl;
12326f50fbeSSimon Glass 	int ret;
12426f50fbeSSimon Glass 
12526f50fbeSSimon Glass 	/* Set up pin control if available */
12626f50fbeSSimon Glass 	ret = syscon_get_by_driver_data(X86_SYSCON_PINCONF, &pinctrl);
12726f50fbeSSimon Glass 	debug("%s, pinctrl=%p, ret=%d\n", __func__, pinctrl, ret);
12864b17977SSimon Glass 
12964b17977SSimon Glass 	uc_priv->gpio_count = GPIO_PER_BANK;
13064b17977SSimon Glass 	uc_priv->bank_name = plat->bank_name;
13164b17977SSimon Glass 
13264b17977SSimon Glass 	priv->regs = (struct pch_lp_gpio_regs *)(uintptr_t)plat->base_addr;
13364b17977SSimon Glass 	priv->bank = plat->bank;
13464b17977SSimon Glass 	priv->offset = priv->bank * 32;
13564b17977SSimon Glass 	debug("%s: probe done, regs %p, bank %d\n", __func__, priv->regs,
13664b17977SSimon Glass 	      priv->bank);
13764b17977SSimon Glass 
13864b17977SSimon Glass 	return 0;
13964b17977SSimon Glass }
14064b17977SSimon Glass 
broadwell_gpio_ofdata_to_platdata(struct udevice * dev)14164b17977SSimon Glass static int broadwell_gpio_ofdata_to_platdata(struct udevice *dev)
14264b17977SSimon Glass {
14364b17977SSimon Glass 	struct broadwell_bank_platdata *plat = dev_get_platdata(dev);
14464b17977SSimon Glass 	u32 gpiobase;
14564b17977SSimon Glass 	int bank;
14664b17977SSimon Glass 	int ret;
14764b17977SSimon Glass 
14864b17977SSimon Glass 	ret = pch_get_gpio_base(dev->parent, &gpiobase);
14964b17977SSimon Glass 	if (ret)
15064b17977SSimon Glass 		return ret;
15164b17977SSimon Glass 
152*e160f7d4SSimon Glass 	bank = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "reg", -1);
15364b17977SSimon Glass 	if (bank == -1) {
15464b17977SSimon Glass 		debug("%s: Invalid bank number %d\n", __func__, bank);
15564b17977SSimon Glass 		return -EINVAL;
15664b17977SSimon Glass 	}
15764b17977SSimon Glass 	plat->bank = bank;
15864b17977SSimon Glass 	plat->base_addr = gpiobase;
159*e160f7d4SSimon Glass 	plat->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
16064b17977SSimon Glass 				      "bank-name", NULL);
16164b17977SSimon Glass 
16264b17977SSimon Glass 	return 0;
16364b17977SSimon Glass }
16464b17977SSimon Glass 
16564b17977SSimon Glass static const struct dm_gpio_ops gpio_broadwell_ops = {
16664b17977SSimon Glass 	.request		= broadwell_gpio_request,
16764b17977SSimon Glass 	.direction_input	= broadwell_gpio_direction_input,
16864b17977SSimon Glass 	.direction_output	= broadwell_gpio_direction_output,
16964b17977SSimon Glass 	.get_value		= broadwell_gpio_get_value,
17064b17977SSimon Glass 	.set_value		= broadwell_gpio_set_value,
17164b17977SSimon Glass 	.get_function		= broadwell_gpio_get_function,
17264b17977SSimon Glass };
17364b17977SSimon Glass 
17464b17977SSimon Glass static const struct udevice_id intel_broadwell_gpio_ids[] = {
17564b17977SSimon Glass 	{ .compatible = "intel,broadwell-gpio" },
17664b17977SSimon Glass 	{ }
17764b17977SSimon Glass };
17864b17977SSimon Glass 
17964b17977SSimon Glass U_BOOT_DRIVER(gpio_broadwell) = {
18064b17977SSimon Glass 	.name	= "gpio_broadwell",
18164b17977SSimon Glass 	.id	= UCLASS_GPIO,
18264b17977SSimon Glass 	.of_match = intel_broadwell_gpio_ids,
18364b17977SSimon Glass 	.ops	= &gpio_broadwell_ops,
18464b17977SSimon Glass 	.ofdata_to_platdata	= broadwell_gpio_ofdata_to_platdata,
18564b17977SSimon Glass 	.probe	= broadwell_gpio_probe,
18664b17977SSimon Glass 	.priv_auto_alloc_size = sizeof(struct broadwell_bank_priv),
18764b17977SSimon Glass 	.platdata_auto_alloc_size = sizeof(struct broadwell_bank_platdata),
18864b17977SSimon Glass };
189