cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

rfkill-gpio.c (4078B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (c) 2011, NVIDIA Corporation.
      4 */
      5
      6#include <linux/init.h>
      7#include <linux/kernel.h>
      8#include <linux/module.h>
      9#include <linux/mod_devicetable.h>
     10#include <linux/rfkill.h>
     11#include <linux/platform_device.h>
     12#include <linux/clk.h>
     13#include <linux/slab.h>
     14#include <linux/acpi.h>
     15#include <linux/gpio/consumer.h>
     16
     17struct rfkill_gpio_data {
     18	const char		*name;
     19	enum rfkill_type	type;
     20	struct gpio_desc	*reset_gpio;
     21	struct gpio_desc	*shutdown_gpio;
     22
     23	struct rfkill		*rfkill_dev;
     24	struct clk		*clk;
     25
     26	bool			clk_enabled;
     27};
     28
     29static int rfkill_gpio_set_power(void *data, bool blocked)
     30{
     31	struct rfkill_gpio_data *rfkill = data;
     32
     33	if (!blocked && !IS_ERR(rfkill->clk) && !rfkill->clk_enabled)
     34		clk_enable(rfkill->clk);
     35
     36	gpiod_set_value_cansleep(rfkill->shutdown_gpio, !blocked);
     37	gpiod_set_value_cansleep(rfkill->reset_gpio, !blocked);
     38
     39	if (blocked && !IS_ERR(rfkill->clk) && rfkill->clk_enabled)
     40		clk_disable(rfkill->clk);
     41
     42	rfkill->clk_enabled = !blocked;
     43
     44	return 0;
     45}
     46
     47static const struct rfkill_ops rfkill_gpio_ops = {
     48	.set_block = rfkill_gpio_set_power,
     49};
     50
     51static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
     52static const struct acpi_gpio_params shutdown_gpios = { 1, 0, false };
     53
     54static const struct acpi_gpio_mapping acpi_rfkill_default_gpios[] = {
     55	{ "reset-gpios", &reset_gpios, 1 },
     56	{ "shutdown-gpios", &shutdown_gpios, 1 },
     57	{ },
     58};
     59
     60static int rfkill_gpio_acpi_probe(struct device *dev,
     61				  struct rfkill_gpio_data *rfkill)
     62{
     63	const struct acpi_device_id *id;
     64
     65	id = acpi_match_device(dev->driver->acpi_match_table, dev);
     66	if (!id)
     67		return -ENODEV;
     68
     69	rfkill->type = (unsigned)id->driver_data;
     70
     71	return devm_acpi_dev_add_driver_gpios(dev, acpi_rfkill_default_gpios);
     72}
     73
     74static int rfkill_gpio_probe(struct platform_device *pdev)
     75{
     76	struct rfkill_gpio_data *rfkill;
     77	struct gpio_desc *gpio;
     78	const char *type_name;
     79	int ret;
     80
     81	rfkill = devm_kzalloc(&pdev->dev, sizeof(*rfkill), GFP_KERNEL);
     82	if (!rfkill)
     83		return -ENOMEM;
     84
     85	device_property_read_string(&pdev->dev, "name", &rfkill->name);
     86	device_property_read_string(&pdev->dev, "type", &type_name);
     87
     88	if (!rfkill->name)
     89		rfkill->name = dev_name(&pdev->dev);
     90
     91	rfkill->type = rfkill_find_type(type_name);
     92
     93	if (ACPI_HANDLE(&pdev->dev)) {
     94		ret = rfkill_gpio_acpi_probe(&pdev->dev, rfkill);
     95		if (ret)
     96			return ret;
     97	}
     98
     99	rfkill->clk = devm_clk_get(&pdev->dev, NULL);
    100
    101	gpio = devm_gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
    102	if (IS_ERR(gpio))
    103		return PTR_ERR(gpio);
    104
    105	rfkill->reset_gpio = gpio;
    106
    107	gpio = devm_gpiod_get_optional(&pdev->dev, "shutdown", GPIOD_OUT_LOW);
    108	if (IS_ERR(gpio))
    109		return PTR_ERR(gpio);
    110
    111	rfkill->shutdown_gpio = gpio;
    112
    113	/* Make sure at-least one GPIO is defined for this instance */
    114	if (!rfkill->reset_gpio && !rfkill->shutdown_gpio) {
    115		dev_err(&pdev->dev, "invalid platform data\n");
    116		return -EINVAL;
    117	}
    118
    119	rfkill->rfkill_dev = rfkill_alloc(rfkill->name, &pdev->dev,
    120					  rfkill->type, &rfkill_gpio_ops,
    121					  rfkill);
    122	if (!rfkill->rfkill_dev)
    123		return -ENOMEM;
    124
    125	ret = rfkill_register(rfkill->rfkill_dev);
    126	if (ret < 0)
    127		goto err_destroy;
    128
    129	platform_set_drvdata(pdev, rfkill);
    130
    131	dev_info(&pdev->dev, "%s device registered.\n", rfkill->name);
    132
    133	return 0;
    134
    135err_destroy:
    136	rfkill_destroy(rfkill->rfkill_dev);
    137
    138	return ret;
    139}
    140
    141static int rfkill_gpio_remove(struct platform_device *pdev)
    142{
    143	struct rfkill_gpio_data *rfkill = platform_get_drvdata(pdev);
    144
    145	rfkill_unregister(rfkill->rfkill_dev);
    146	rfkill_destroy(rfkill->rfkill_dev);
    147
    148	return 0;
    149}
    150
    151#ifdef CONFIG_ACPI
    152static const struct acpi_device_id rfkill_acpi_match[] = {
    153	{ "BCM4752", RFKILL_TYPE_GPS },
    154	{ "LNV4752", RFKILL_TYPE_GPS },
    155	{ },
    156};
    157MODULE_DEVICE_TABLE(acpi, rfkill_acpi_match);
    158#endif
    159
    160static struct platform_driver rfkill_gpio_driver = {
    161	.probe = rfkill_gpio_probe,
    162	.remove = rfkill_gpio_remove,
    163	.driver = {
    164		.name = "rfkill_gpio",
    165		.acpi_match_table = ACPI_PTR(rfkill_acpi_match),
    166	},
    167};
    168
    169module_platform_driver(rfkill_gpio_driver);
    170
    171MODULE_DESCRIPTION("gpio rfkill");
    172MODULE_AUTHOR("NVIDIA");
    173MODULE_LICENSE("GPL");