linux/drivers/input/keyboard/cypress-sf.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Cypress StreetFighter Touchkey Driver
 *
 * Copyright (c) 2021 Yassine Oudjana <[email protected]>
 */

#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/regulator/consumer.h>

#define CYPRESS_SF_DEV_NAME

#define CYPRESS_SF_REG_BUTTON_STATUS

struct cypress_sf_data {};

static irqreturn_t cypress_sf_irq_handler(int irq, void *devid)
{}

static void cypress_sf_disable_regulators(void *arg)
{}

static int cypress_sf_probe(struct i2c_client *client)
{
	struct cypress_sf_data *touchkey;
	int key, error;

	touchkey = devm_kzalloc(&client->dev, sizeof(*touchkey), GFP_KERNEL);
	if (!touchkey)
		return -ENOMEM;

	touchkey->client = client;
	i2c_set_clientdata(client, touchkey);

	touchkey->regulators[0].supply = "vdd";
	touchkey->regulators[1].supply = "avdd";

	error = devm_regulator_bulk_get(&client->dev,
					ARRAY_SIZE(touchkey->regulators),
					touchkey->regulators);
	if (error) {
		dev_err(&client->dev, "Failed to get regulators: %d\n", error);
		return error;
	}

	touchkey->num_keys = device_property_read_u32_array(&client->dev,
							    "linux,keycodes",
							    NULL, 0);
	if (touchkey->num_keys < 0) {
		/* Default key count */
		touchkey->num_keys = 2;
	}

	touchkey->keycodes = devm_kcalloc(&client->dev,
					  touchkey->num_keys,
					  sizeof(*touchkey->keycodes),
					  GFP_KERNEL);
	if (!touchkey->keycodes)
		return -ENOMEM;

	error = device_property_read_u32_array(&client->dev, "linux,keycodes",
					       touchkey->keycodes,
					       touchkey->num_keys);

	if (error) {
		dev_warn(&client->dev,
			 "Failed to read keycodes: %d, using defaults\n",
			 error);

		/* Default keycodes */
		touchkey->keycodes[0] = KEY_BACK;
		touchkey->keycodes[1] = KEY_MENU;
	}

	error = regulator_bulk_enable(ARRAY_SIZE(touchkey->regulators),
				      touchkey->regulators);
	if (error) {
		dev_err(&client->dev,
			"Failed to enable regulators: %d\n", error);
		return error;
	}

	error = devm_add_action_or_reset(&client->dev,
					 cypress_sf_disable_regulators,
					 touchkey);
	if (error)
		return error;

	touchkey->input_dev = devm_input_allocate_device(&client->dev);
	if (!touchkey->input_dev) {
		dev_err(&client->dev, "Failed to allocate input device\n");
		return -ENOMEM;
	}

	touchkey->input_dev->name = CYPRESS_SF_DEV_NAME;
	touchkey->input_dev->id.bustype = BUS_I2C;

	for (key = 0; key < touchkey->num_keys; ++key)
		input_set_capability(touchkey->input_dev,
				     EV_KEY, touchkey->keycodes[key]);

	error = input_register_device(touchkey->input_dev);
	if (error) {
		dev_err(&client->dev,
			"Failed to register input device: %d\n", error);
		return error;
	}

	error = devm_request_threaded_irq(&client->dev, client->irq,
					  NULL, cypress_sf_irq_handler,
					  IRQF_ONESHOT,
					  CYPRESS_SF_DEV_NAME, touchkey);
	if (error) {
		dev_err(&client->dev,
			"Failed to register threaded irq: %d", error);
		return error;
	}

	return 0;
};

static int cypress_sf_suspend(struct device *dev)
{}

static int cypress_sf_resume(struct device *dev)
{}

static DEFINE_SIMPLE_DEV_PM_OPS(cypress_sf_pm_ops,
				cypress_sf_suspend, cypress_sf_resume);

static struct i2c_device_id cypress_sf_id_table[] =;
MODULE_DEVICE_TABLE(i2c, cypress_sf_id_table);

#ifdef CONFIG_OF
static const struct of_device_id cypress_sf_of_match[] =;
MODULE_DEVICE_TABLE(of, cypress_sf_of_match);
#endif

static struct i2c_driver cypress_sf_driver =;
module_i2c_driver();

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();