/* * Example stub i2c driver * * Copyright (c) 2015 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Red Hat authors: * Hans de Goede */ #include #include #include #include #include struct stub_data { struct i2c_client *client; struct gpio_desc *wake_gpio; /* Add driver data here */ }; static irqreturn_t stub_irq(int irq, void *dev_id) { struct stub_data *data = dev_id; struct device *dev = &data->client->dev; dev_info(dev, "OOB interrupt triggered\n"); return IRQ_HANDLED; } static void stub_start(struct stub_data *data) { enable_irq(data->client->irq); gpiod_set_value_cansleep(data->wake_gpio, 1); } static void stub_stop(struct stub_data *data) { disable_irq(data->client->irq); gpiod_set_value_cansleep(data->wake_gpio, 0); } #ifdef CONFIG_PM_SLEEP static int stub_suspend(struct device *dev) { struct stub_data *data = i2c_get_clientdata(to_i2c_client(dev)); stub_stop(data); return 0; } static int stub_resume(struct device *dev) { struct stub_data *data = i2c_get_clientdata(to_i2c_client(dev)); stub_start(data); return 0; } #endif static SIMPLE_DEV_PM_OPS(stub_pm_ops, stub_suspend, stub_resume); static int stub_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; struct stub_data *data; int error; if (!client->irq) { dev_err(dev, "Error no irq specified\n"); return -EINVAL; } data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; data->wake_gpio = devm_gpiod_get(dev, "wake", GPIOD_OUT_LOW); if (IS_ERR(data->wake_gpio)) { error = PTR_ERR(data->wake_gpio); if (error != -EPROBE_DEFER) dev_err(dev, "Error getting wake gpio: %d\n", error); return error; } data->client = client; error = devm_request_threaded_irq(dev, client->irq, NULL, stub_irq, IRQF_ONESHOT, client->name, data); if (error) { dev_err(dev, "Error requesting irq: %d\n", error); return error; } i2c_set_clientdata(client, data); dev_info(dev, "Stub i2c device Stub Model successfully initialized\n"); return 0; } static const struct of_device_id stub_of_match[] = { { .compatible = "stub,stub-model" }, { } }; MODULE_DEVICE_TABLE(of, stub_of_match); /* This is useless for OF-enabled devices, but it is needed by I2C subsystem */ static const struct i2c_device_id stub_i2c_id[] = { { }, }; MODULE_DEVICE_TABLE(i2c, stub_i2c_id); static struct i2c_driver stub_driver = { .driver = { .owner = THIS_MODULE, .name = "stub_stub_model", .pm = &stub_pm_ops, .of_match_table = stub_of_match, }, .probe = stub_probe, .id_table = stub_i2c_id, }; module_i2c_driver(stub_driver); MODULE_DESCRIPTION("Basic stub I2C driver"); MODULE_AUTHOR("Hans de Goede "); MODULE_LICENSE("GPL");