162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * lis3lv02d_spi - SPI glue layer for lis3lv02d 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/err.h> 1162306a36Sopenharmony_ci#include <linux/input.h> 1262306a36Sopenharmony_ci#include <linux/interrupt.h> 1362306a36Sopenharmony_ci#include <linux/workqueue.h> 1462306a36Sopenharmony_ci#include <linux/spi/spi.h> 1562306a36Sopenharmony_ci#include <linux/pm.h> 1662306a36Sopenharmony_ci#include <linux/of.h> 1762306a36Sopenharmony_ci#include <linux/of_platform.h> 1862306a36Sopenharmony_ci#include <linux/of_device.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "lis3lv02d.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define DRV_NAME "lis3lv02d_spi" 2362306a36Sopenharmony_ci#define LIS3_SPI_READ 0x80 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic int lis3_spi_read(struct lis3lv02d *lis3, int reg, u8 *v) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci struct spi_device *spi = lis3->bus_priv; 2862306a36Sopenharmony_ci int ret = spi_w8r8(spi, reg | LIS3_SPI_READ); 2962306a36Sopenharmony_ci if (ret < 0) 3062306a36Sopenharmony_ci return -EINVAL; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci *v = (u8) ret; 3362306a36Sopenharmony_ci return 0; 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic int lis3_spi_write(struct lis3lv02d *lis3, int reg, u8 val) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci u8 tmp[2] = { reg, val }; 3962306a36Sopenharmony_ci struct spi_device *spi = lis3->bus_priv; 4062306a36Sopenharmony_ci return spi_write(spi, tmp, sizeof(tmp)); 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic int lis3_spi_init(struct lis3lv02d *lis3) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci u8 reg; 4662306a36Sopenharmony_ci int ret; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* power up the device */ 4962306a36Sopenharmony_ci ret = lis3->read(lis3, CTRL_REG1, ®); 5062306a36Sopenharmony_ci if (ret < 0) 5162306a36Sopenharmony_ci return ret; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen; 5462306a36Sopenharmony_ci return lis3->write(lis3, CTRL_REG1, reg); 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic union axis_conversion lis3lv02d_axis_normal = 5862306a36Sopenharmony_ci { .as_array = { 1, 2, 3 } }; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#ifdef CONFIG_OF 6162306a36Sopenharmony_cistatic const struct of_device_id lis302dl_spi_dt_ids[] = { 6262306a36Sopenharmony_ci { .compatible = "st,lis302dl-spi" }, 6362306a36Sopenharmony_ci {} 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, lis302dl_spi_dt_ids); 6662306a36Sopenharmony_ci#endif 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic int lis302dl_spi_probe(struct spi_device *spi) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci int ret; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci spi->bits_per_word = 8; 7362306a36Sopenharmony_ci spi->mode = SPI_MODE_0; 7462306a36Sopenharmony_ci ret = spi_setup(spi); 7562306a36Sopenharmony_ci if (ret < 0) 7662306a36Sopenharmony_ci return ret; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci lis3_dev.bus_priv = spi; 7962306a36Sopenharmony_ci lis3_dev.init = lis3_spi_init; 8062306a36Sopenharmony_ci lis3_dev.read = lis3_spi_read; 8162306a36Sopenharmony_ci lis3_dev.write = lis3_spi_write; 8262306a36Sopenharmony_ci lis3_dev.irq = spi->irq; 8362306a36Sopenharmony_ci lis3_dev.ac = lis3lv02d_axis_normal; 8462306a36Sopenharmony_ci lis3_dev.pdata = spi->dev.platform_data; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#ifdef CONFIG_OF 8762306a36Sopenharmony_ci if (of_match_device(lis302dl_spi_dt_ids, &spi->dev)) { 8862306a36Sopenharmony_ci lis3_dev.of_node = spi->dev.of_node; 8962306a36Sopenharmony_ci ret = lis3lv02d_init_dt(&lis3_dev); 9062306a36Sopenharmony_ci if (ret) 9162306a36Sopenharmony_ci return ret; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci#endif 9462306a36Sopenharmony_ci spi_set_drvdata(spi, &lis3_dev); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci return lis3lv02d_init_device(&lis3_dev); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic void lis302dl_spi_remove(struct spi_device *spi) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct lis3lv02d *lis3 = spi_get_drvdata(spi); 10262306a36Sopenharmony_ci lis3lv02d_joystick_disable(lis3); 10362306a36Sopenharmony_ci lis3lv02d_poweroff(lis3); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci lis3lv02d_remove_fs(&lis3_dev); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 10962306a36Sopenharmony_cistatic int lis3lv02d_spi_suspend(struct device *dev) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct spi_device *spi = to_spi_device(dev); 11262306a36Sopenharmony_ci struct lis3lv02d *lis3 = spi_get_drvdata(spi); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (!lis3->pdata || !lis3->pdata->wakeup_flags) 11562306a36Sopenharmony_ci lis3lv02d_poweroff(&lis3_dev); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return 0; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic int lis3lv02d_spi_resume(struct device *dev) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct spi_device *spi = to_spi_device(dev); 12362306a36Sopenharmony_ci struct lis3lv02d *lis3 = spi_get_drvdata(spi); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (!lis3->pdata || !lis3->pdata->wakeup_flags) 12662306a36Sopenharmony_ci lis3lv02d_poweron(lis3); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci return 0; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci#endif 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(lis3lv02d_spi_pm, lis3lv02d_spi_suspend, 13362306a36Sopenharmony_ci lis3lv02d_spi_resume); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic struct spi_driver lis302dl_spi_driver = { 13662306a36Sopenharmony_ci .driver = { 13762306a36Sopenharmony_ci .name = DRV_NAME, 13862306a36Sopenharmony_ci .pm = &lis3lv02d_spi_pm, 13962306a36Sopenharmony_ci .of_match_table = of_match_ptr(lis302dl_spi_dt_ids), 14062306a36Sopenharmony_ci }, 14162306a36Sopenharmony_ci .probe = lis302dl_spi_probe, 14262306a36Sopenharmony_ci .remove = lis302dl_spi_remove, 14362306a36Sopenharmony_ci}; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cimodule_spi_driver(lis302dl_spi_driver); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ciMODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); 14862306a36Sopenharmony_ciMODULE_DESCRIPTION("lis3lv02d SPI glue layer"); 14962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 15062306a36Sopenharmony_ciMODULE_ALIAS("spi:" DRV_NAME); 151