1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * lis3lv02d_spi - SPI glue layer for lis3lv02d |
4 | * |
5 | * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> |
6 | */ |
7 | |
8 | #include <linux/module.h> |
9 | #include <linux/kernel.h> |
10 | #include <linux/err.h> |
11 | #include <linux/input.h> |
12 | #include <linux/interrupt.h> |
13 | #include <linux/workqueue.h> |
14 | #include <linux/spi/spi.h> |
15 | #include <linux/pm.h> |
16 | #include <linux/of.h> |
17 | #include <linux/of_platform.h> |
18 | #include <linux/of_device.h> |
19 | |
20 | #include "lis3lv02d.h" |
21 | |
22 | #define DRV_NAME "lis3lv02d_spi" |
23 | #define LIS3_SPI_READ 0x80 |
24 | |
25 | static int lis3_spi_read(struct lis3lv02d *lis3, int reg, u8 *v) |
26 | { |
27 | struct spi_device *spi = lis3->bus_priv; |
28 | int ret = spi_w8r8(spi, cmd: reg | LIS3_SPI_READ); |
29 | if (ret < 0) |
30 | return -EINVAL; |
31 | |
32 | *v = (u8) ret; |
33 | return 0; |
34 | } |
35 | |
36 | static int lis3_spi_write(struct lis3lv02d *lis3, int reg, u8 val) |
37 | { |
38 | u8 tmp[2] = { reg, val }; |
39 | struct spi_device *spi = lis3->bus_priv; |
40 | return spi_write(spi, buf: tmp, len: sizeof(tmp)); |
41 | } |
42 | |
43 | static int lis3_spi_init(struct lis3lv02d *lis3) |
44 | { |
45 | u8 reg; |
46 | int ret; |
47 | |
48 | /* power up the device */ |
49 | ret = lis3->read(lis3, CTRL_REG1, ®); |
50 | if (ret < 0) |
51 | return ret; |
52 | |
53 | reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen; |
54 | return lis3->write(lis3, CTRL_REG1, reg); |
55 | } |
56 | |
57 | static union axis_conversion lis3lv02d_axis_normal = |
58 | { .as_array = { 1, 2, 3 } }; |
59 | |
60 | #ifdef CONFIG_OF |
61 | static const struct of_device_id lis302dl_spi_dt_ids[] = { |
62 | { .compatible = "st,lis302dl-spi" }, |
63 | {} |
64 | }; |
65 | MODULE_DEVICE_TABLE(of, lis302dl_spi_dt_ids); |
66 | #endif |
67 | |
68 | static int lis302dl_spi_probe(struct spi_device *spi) |
69 | { |
70 | int ret; |
71 | |
72 | spi->bits_per_word = 8; |
73 | spi->mode = SPI_MODE_0; |
74 | ret = spi_setup(spi); |
75 | if (ret < 0) |
76 | return ret; |
77 | |
78 | lis3_dev.bus_priv = spi; |
79 | lis3_dev.init = lis3_spi_init; |
80 | lis3_dev.read = lis3_spi_read; |
81 | lis3_dev.write = lis3_spi_write; |
82 | lis3_dev.irq = spi->irq; |
83 | lis3_dev.ac = lis3lv02d_axis_normal; |
84 | lis3_dev.pdata = spi->dev.platform_data; |
85 | |
86 | #ifdef CONFIG_OF |
87 | if (of_match_device(matches: lis302dl_spi_dt_ids, dev: &spi->dev)) { |
88 | lis3_dev.of_node = spi->dev.of_node; |
89 | ret = lis3lv02d_init_dt(lis3: &lis3_dev); |
90 | if (ret) |
91 | return ret; |
92 | } |
93 | #endif |
94 | spi_set_drvdata(spi, data: &lis3_dev); |
95 | |
96 | return lis3lv02d_init_device(lis3: &lis3_dev); |
97 | } |
98 | |
99 | static void lis302dl_spi_remove(struct spi_device *spi) |
100 | { |
101 | struct lis3lv02d *lis3 = spi_get_drvdata(spi); |
102 | lis3lv02d_joystick_disable(lis3); |
103 | lis3lv02d_poweroff(lis3); |
104 | |
105 | lis3lv02d_remove_fs(lis3: &lis3_dev); |
106 | } |
107 | |
108 | #ifdef CONFIG_PM_SLEEP |
109 | static int lis3lv02d_spi_suspend(struct device *dev) |
110 | { |
111 | struct spi_device *spi = to_spi_device(dev); |
112 | struct lis3lv02d *lis3 = spi_get_drvdata(spi); |
113 | |
114 | if (!lis3->pdata || !lis3->pdata->wakeup_flags) |
115 | lis3lv02d_poweroff(lis3: &lis3_dev); |
116 | |
117 | return 0; |
118 | } |
119 | |
120 | static int lis3lv02d_spi_resume(struct device *dev) |
121 | { |
122 | struct spi_device *spi = to_spi_device(dev); |
123 | struct lis3lv02d *lis3 = spi_get_drvdata(spi); |
124 | |
125 | if (!lis3->pdata || !lis3->pdata->wakeup_flags) |
126 | lis3lv02d_poweron(lis3); |
127 | |
128 | return 0; |
129 | } |
130 | #endif |
131 | |
132 | static SIMPLE_DEV_PM_OPS(lis3lv02d_spi_pm, lis3lv02d_spi_suspend, |
133 | lis3lv02d_spi_resume); |
134 | |
135 | static struct spi_driver lis302dl_spi_driver = { |
136 | .driver = { |
137 | .name = DRV_NAME, |
138 | .pm = &lis3lv02d_spi_pm, |
139 | .of_match_table = of_match_ptr(lis302dl_spi_dt_ids), |
140 | }, |
141 | .probe = lis302dl_spi_probe, |
142 | .remove = lis302dl_spi_remove, |
143 | }; |
144 | |
145 | module_spi_driver(lis302dl_spi_driver); |
146 | |
147 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>" ); |
148 | MODULE_DESCRIPTION("lis3lv02d SPI glue layer" ); |
149 | MODULE_LICENSE("GPL" ); |
150 | MODULE_ALIAS("spi:" DRV_NAME); |
151 | |