18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * lis3lv02d_spi - SPI glue layer for lis3lv02d 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/err.h> 118c2ecf20Sopenharmony_ci#include <linux/input.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 148c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 158c2ecf20Sopenharmony_ci#include <linux/pm.h> 168c2ecf20Sopenharmony_ci#include <linux/of.h> 178c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 188c2ecf20Sopenharmony_ci#include <linux/of_device.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "lis3lv02d.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define DRV_NAME "lis3lv02d_spi" 238c2ecf20Sopenharmony_ci#define LIS3_SPI_READ 0x80 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic int lis3_spi_read(struct lis3lv02d *lis3, int reg, u8 *v) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci struct spi_device *spi = lis3->bus_priv; 288c2ecf20Sopenharmony_ci int ret = spi_w8r8(spi, reg | LIS3_SPI_READ); 298c2ecf20Sopenharmony_ci if (ret < 0) 308c2ecf20Sopenharmony_ci return -EINVAL; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci *v = (u8) ret; 338c2ecf20Sopenharmony_ci return 0; 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic int lis3_spi_write(struct lis3lv02d *lis3, int reg, u8 val) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci u8 tmp[2] = { reg, val }; 398c2ecf20Sopenharmony_ci struct spi_device *spi = lis3->bus_priv; 408c2ecf20Sopenharmony_ci return spi_write(spi, tmp, sizeof(tmp)); 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic int lis3_spi_init(struct lis3lv02d *lis3) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci u8 reg; 468c2ecf20Sopenharmony_ci int ret; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* power up the device */ 498c2ecf20Sopenharmony_ci ret = lis3->read(lis3, CTRL_REG1, ®); 508c2ecf20Sopenharmony_ci if (ret < 0) 518c2ecf20Sopenharmony_ci return ret; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen; 548c2ecf20Sopenharmony_ci return lis3->write(lis3, CTRL_REG1, reg); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic union axis_conversion lis3lv02d_axis_normal = 588c2ecf20Sopenharmony_ci { .as_array = { 1, 2, 3 } }; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 618c2ecf20Sopenharmony_cistatic const struct of_device_id lis302dl_spi_dt_ids[] = { 628c2ecf20Sopenharmony_ci { .compatible = "st,lis302dl-spi" }, 638c2ecf20Sopenharmony_ci {} 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, lis302dl_spi_dt_ids); 668c2ecf20Sopenharmony_ci#endif 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic int lis302dl_spi_probe(struct spi_device *spi) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci int ret; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci spi->bits_per_word = 8; 738c2ecf20Sopenharmony_ci spi->mode = SPI_MODE_0; 748c2ecf20Sopenharmony_ci ret = spi_setup(spi); 758c2ecf20Sopenharmony_ci if (ret < 0) 768c2ecf20Sopenharmony_ci return ret; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci lis3_dev.bus_priv = spi; 798c2ecf20Sopenharmony_ci lis3_dev.init = lis3_spi_init; 808c2ecf20Sopenharmony_ci lis3_dev.read = lis3_spi_read; 818c2ecf20Sopenharmony_ci lis3_dev.write = lis3_spi_write; 828c2ecf20Sopenharmony_ci lis3_dev.irq = spi->irq; 838c2ecf20Sopenharmony_ci lis3_dev.ac = lis3lv02d_axis_normal; 848c2ecf20Sopenharmony_ci lis3_dev.pdata = spi->dev.platform_data; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 878c2ecf20Sopenharmony_ci if (of_match_device(lis302dl_spi_dt_ids, &spi->dev)) { 888c2ecf20Sopenharmony_ci lis3_dev.of_node = spi->dev.of_node; 898c2ecf20Sopenharmony_ci ret = lis3lv02d_init_dt(&lis3_dev); 908c2ecf20Sopenharmony_ci if (ret) 918c2ecf20Sopenharmony_ci return ret; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci#endif 948c2ecf20Sopenharmony_ci spi_set_drvdata(spi, &lis3_dev); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return lis3lv02d_init_device(&lis3_dev); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int lis302dl_spi_remove(struct spi_device *spi) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci struct lis3lv02d *lis3 = spi_get_drvdata(spi); 1028c2ecf20Sopenharmony_ci lis3lv02d_joystick_disable(lis3); 1038c2ecf20Sopenharmony_ci lis3lv02d_poweroff(lis3); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci return lis3lv02d_remove_fs(&lis3_dev); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 1098c2ecf20Sopenharmony_cistatic int lis3lv02d_spi_suspend(struct device *dev) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct spi_device *spi = to_spi_device(dev); 1128c2ecf20Sopenharmony_ci struct lis3lv02d *lis3 = spi_get_drvdata(spi); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (!lis3->pdata || !lis3->pdata->wakeup_flags) 1158c2ecf20Sopenharmony_ci lis3lv02d_poweroff(&lis3_dev); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return 0; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic int lis3lv02d_spi_resume(struct device *dev) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci struct spi_device *spi = to_spi_device(dev); 1238c2ecf20Sopenharmony_ci struct lis3lv02d *lis3 = spi_get_drvdata(spi); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (!lis3->pdata || !lis3->pdata->wakeup_flags) 1268c2ecf20Sopenharmony_ci lis3lv02d_poweron(lis3); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci return 0; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci#endif 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(lis3lv02d_spi_pm, lis3lv02d_spi_suspend, 1338c2ecf20Sopenharmony_ci lis3lv02d_spi_resume); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic struct spi_driver lis302dl_spi_driver = { 1368c2ecf20Sopenharmony_ci .driver = { 1378c2ecf20Sopenharmony_ci .name = DRV_NAME, 1388c2ecf20Sopenharmony_ci .pm = &lis3lv02d_spi_pm, 1398c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(lis302dl_spi_dt_ids), 1408c2ecf20Sopenharmony_ci }, 1418c2ecf20Sopenharmony_ci .probe = lis302dl_spi_probe, 1428c2ecf20Sopenharmony_ci .remove = lis302dl_spi_remove, 1438c2ecf20Sopenharmony_ci}; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cimodule_spi_driver(lis302dl_spi_driver); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ciMODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); 1488c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("lis3lv02d SPI glue layer"); 1498c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1508c2ecf20Sopenharmony_ciMODULE_ALIAS("spi:" DRV_NAME); 151