1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * ADLX345/346 Three-Axis Digital Accelerometers (SPI Interface) |
4 | * |
5 | * Enter bugs at http://blackfin.uclinux.org/ |
6 | * |
7 | * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc. |
8 | */ |
9 | |
10 | #include <linux/input.h> /* BUS_SPI */ |
11 | #include <linux/module.h> |
12 | #include <linux/spi/spi.h> |
13 | #include <linux/pm.h> |
14 | #include <linux/types.h> |
15 | #include "adxl34x.h" |
16 | |
17 | #define MAX_SPI_FREQ_HZ 5000000 |
18 | #define MAX_FREQ_NO_FIFODELAY 1500000 |
19 | #define ADXL34X_CMD_MULTB (1 << 6) |
20 | #define ADXL34X_CMD_READ (1 << 7) |
21 | #define ADXL34X_WRITECMD(reg) (reg & 0x3F) |
22 | #define ADXL34X_READCMD(reg) (ADXL34X_CMD_READ | (reg & 0x3F)) |
23 | #define ADXL34X_READMB_CMD(reg) (ADXL34X_CMD_READ | ADXL34X_CMD_MULTB \ |
24 | | (reg & 0x3F)) |
25 | |
26 | static int adxl34x_spi_read(struct device *dev, unsigned char reg) |
27 | { |
28 | struct spi_device *spi = to_spi_device(dev); |
29 | unsigned char cmd; |
30 | |
31 | cmd = ADXL34X_READCMD(reg); |
32 | |
33 | return spi_w8r8(spi, cmd); |
34 | } |
35 | |
36 | static int adxl34x_spi_write(struct device *dev, |
37 | unsigned char reg, unsigned char val) |
38 | { |
39 | struct spi_device *spi = to_spi_device(dev); |
40 | unsigned char buf[2]; |
41 | |
42 | buf[0] = ADXL34X_WRITECMD(reg); |
43 | buf[1] = val; |
44 | |
45 | return spi_write(spi, buf, len: sizeof(buf)); |
46 | } |
47 | |
48 | static int adxl34x_spi_read_block(struct device *dev, |
49 | unsigned char reg, int count, |
50 | void *buf) |
51 | { |
52 | struct spi_device *spi = to_spi_device(dev); |
53 | ssize_t status; |
54 | |
55 | reg = ADXL34X_READMB_CMD(reg); |
56 | status = spi_write_then_read(spi, txbuf: ®, n_tx: 1, rxbuf: buf, n_rx: count); |
57 | |
58 | return (status < 0) ? status : 0; |
59 | } |
60 | |
61 | static const struct adxl34x_bus_ops adxl34x_spi_bops = { |
62 | .bustype = BUS_SPI, |
63 | .write = adxl34x_spi_write, |
64 | .read = adxl34x_spi_read, |
65 | .read_block = adxl34x_spi_read_block, |
66 | }; |
67 | |
68 | static int adxl34x_spi_probe(struct spi_device *spi) |
69 | { |
70 | struct adxl34x *ac; |
71 | |
72 | /* don't exceed max specified SPI CLK frequency */ |
73 | if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) { |
74 | dev_err(&spi->dev, "SPI CLK %d Hz too fast\n" , spi->max_speed_hz); |
75 | return -EINVAL; |
76 | } |
77 | |
78 | ac = adxl34x_probe(dev: &spi->dev, irq: spi->irq, |
79 | fifo_delay_default: spi->max_speed_hz > MAX_FREQ_NO_FIFODELAY, |
80 | bops: &adxl34x_spi_bops); |
81 | |
82 | if (IS_ERR(ptr: ac)) |
83 | return PTR_ERR(ptr: ac); |
84 | |
85 | spi_set_drvdata(spi, data: ac); |
86 | |
87 | return 0; |
88 | } |
89 | |
90 | static void adxl34x_spi_remove(struct spi_device *spi) |
91 | { |
92 | struct adxl34x *ac = spi_get_drvdata(spi); |
93 | |
94 | adxl34x_remove(ac); |
95 | } |
96 | |
97 | static struct spi_driver adxl34x_driver = { |
98 | .driver = { |
99 | .name = "adxl34x" , |
100 | .pm = pm_sleep_ptr(&adxl34x_pm), |
101 | }, |
102 | .probe = adxl34x_spi_probe, |
103 | .remove = adxl34x_spi_remove, |
104 | }; |
105 | |
106 | module_spi_driver(adxl34x_driver); |
107 | |
108 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>" ); |
109 | MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer SPI Bus Driver" ); |
110 | MODULE_LICENSE("GPL" ); |
111 | |