brintos

brintos / linux-shallow public Read only

0
0
Text · 5.3 KiB · 016a9f6 Raw
225 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Intel PCH pinctrl/GPIO driver4 *5 * Copyright (C) 2021-2023, Intel Corporation6 * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>7 */8 9#include <linux/mod_devicetable.h>10#include <linux/module.h>11#include <linux/platform_device.h>12#include <linux/pm.h>13#include <linux/property.h>14#include <linux/string_helpers.h>15 16#include <linux/pinctrl/pinctrl.h>17 18#include "pinctrl-intel.h"19 20struct intel_platform_pins {21	struct pinctrl_pin_desc *pins;22	size_t npins;23};24 25static int intel_platform_pinctrl_prepare_pins(struct device *dev, size_t base,26					       const char *name, u32 size,27					       struct intel_platform_pins *pins)28{29	struct pinctrl_pin_desc *descs;30	char **pin_names;31	unsigned int i;32 33	pin_names = devm_kasprintf_strarray(dev, name, size);34	if (IS_ERR(pin_names))35		return PTR_ERR(pin_names);36 37	descs = devm_krealloc_array(dev, pins->pins, base + size, sizeof(*descs), GFP_KERNEL);38	if (!descs)39		return -ENOMEM;40 41	for (i = 0; i < size; i++) {42		unsigned int pin_number = base + i;43		char *pin_name = pin_names[i];44		struct pinctrl_pin_desc *desc;45 46		/* Unify delimiter for pin name */47		strreplace(pin_name, '-', '_');48 49		desc = &descs[pin_number];50		desc->number = pin_number;51		desc->name = pin_name;52	}53 54	pins->pins = descs;55	pins->npins = base + size;56 57	return 0;58}59 60static int intel_platform_pinctrl_prepare_group(struct device *dev,61						struct fwnode_handle *child,62						struct intel_padgroup *gpp,63						struct intel_platform_pins *pins)64{65	size_t base = pins->npins;66	const char *name;67	u32 size;68	int ret;69 70	ret = fwnode_property_read_string(child, "intc-gpio-group-name", &name);71	if (ret)72		return ret;73 74	ret = fwnode_property_read_u32(child, "intc-gpio-pad-count", &size);75	if (ret)76		return ret;77 78	ret = intel_platform_pinctrl_prepare_pins(dev, base, name, size, pins);79	if (ret)80		return ret;81 82	gpp->base = base;83	gpp->size = size;84	gpp->gpio_base = INTEL_GPIO_BASE_MATCH;85 86	return 0;87}88 89static int intel_platform_pinctrl_prepare_community(struct device *dev,90						    struct intel_community *community,91						    struct intel_platform_pins *pins)92{93	struct intel_padgroup *gpps;94	unsigned int group;95	size_t ngpps;96	u32 offset;97	int ret;98 99	ret = device_property_read_u32(dev, "intc-gpio-pad-ownership-offset", &offset);100	if (ret)101		return ret;102	community->padown_offset = offset;103 104	ret = device_property_read_u32(dev, "intc-gpio-pad-configuration-lock-offset", &offset);105	if (ret)106		return ret;107	community->padcfglock_offset = offset;108 109	ret = device_property_read_u32(dev, "intc-gpio-host-software-pad-ownership-offset", &offset);110	if (ret)111		return ret;112	community->hostown_offset = offset;113 114	ret = device_property_read_u32(dev, "intc-gpio-gpi-interrupt-status-offset", &offset);115	if (ret)116		return ret;117	community->is_offset = offset;118 119	ret = device_property_read_u32(dev, "intc-gpio-gpi-interrupt-enable-offset", &offset);120	if (ret)121		return ret;122	community->ie_offset = offset;123 124	ngpps = device_get_child_node_count(dev);125	if (!ngpps)126		return -ENODEV;127 128	gpps = devm_kcalloc(dev, ngpps, sizeof(*gpps), GFP_KERNEL);129	if (!gpps)130		return -ENOMEM;131 132	group = 0;133	device_for_each_child_node_scoped(dev, child) {134		struct intel_padgroup *gpp = &gpps[group];135 136		gpp->reg_num = group;137 138		ret = intel_platform_pinctrl_prepare_group(dev, child, gpp, pins);139		if (ret)140			return ret;141 142		group++;143	}144 145	community->ngpps = ngpps;146	community->gpps = gpps;147 148	return 0;149}150 151static int intel_platform_pinctrl_prepare_soc_data(struct device *dev,152						   struct intel_pinctrl_soc_data *data)153{154	struct intel_platform_pins pins = {};155	struct intel_community *communities;156	size_t ncommunities;157	unsigned int i;158	int ret;159 160	/* Version 1.0 of the specification assumes only a single community per device node */161	ncommunities = 1;162	communities = devm_kcalloc(dev, ncommunities, sizeof(*communities), GFP_KERNEL);163	if (!communities)164		return -ENOMEM;165 166	for (i = 0; i < ncommunities; i++) {167		struct intel_community *community = &communities[i];168 169		community->barno = i;170		community->pin_base = pins.npins;171 172		ret = intel_platform_pinctrl_prepare_community(dev, community, &pins);173		if (ret)174			return ret;175 176		community->npins = pins.npins - community->pin_base;177	}178 179	data->ncommunities = ncommunities;180	data->communities = communities;181 182	data->npins = pins.npins;183	data->pins = pins.pins;184 185	return 0;186}187 188static int intel_platform_pinctrl_probe(struct platform_device *pdev)189{190	struct intel_pinctrl_soc_data *data;191	struct device *dev = &pdev->dev;192	int ret;193 194	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);195	if (!data)196		return -ENOMEM;197 198	ret = intel_platform_pinctrl_prepare_soc_data(dev, data);199	if (ret)200		return ret;201 202	return intel_pinctrl_probe(pdev, data);203}204 205static const struct acpi_device_id intel_platform_pinctrl_acpi_match[] = {206	{ "INTC105F" },207	{ }208};209MODULE_DEVICE_TABLE(acpi, intel_platform_pinctrl_acpi_match);210 211static struct platform_driver intel_platform_pinctrl_driver = {212	.probe = intel_platform_pinctrl_probe,213	.driver = {214		.name = "intel-pinctrl",215		.acpi_match_table = intel_platform_pinctrl_acpi_match,216		.pm = pm_sleep_ptr(&intel_pinctrl_pm_ops),217	},218};219module_platform_driver(intel_platform_pinctrl_driver);220 221MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");222MODULE_DESCRIPTION("Intel PCH pinctrl/GPIO driver");223MODULE_LICENSE("GPL v2");224MODULE_IMPORT_NS(PINCTRL_INTEL);225