18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * STMicroelectronics accelerometers driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2012-2013 STMicroelectronics Inc.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Denis Ciocca <denis.ciocca@st.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/slab.h>
138c2ecf20Sopenharmony_ci#include <linux/acpi.h>
148c2ecf20Sopenharmony_ci#include <linux/i2c.h>
158c2ecf20Sopenharmony_ci#include <linux/iio/iio.h>
168c2ecf20Sopenharmony_ci#include <linux/property.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/iio/common/st_sensors_i2c.h>
198c2ecf20Sopenharmony_ci#include "st_accel.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic const struct of_device_id st_accel_of_match[] = {
228c2ecf20Sopenharmony_ci	{
238c2ecf20Sopenharmony_ci		/* An older compatible */
248c2ecf20Sopenharmony_ci		.compatible = "st,lis3lv02d",
258c2ecf20Sopenharmony_ci		.data = LIS3LV02DL_ACCEL_DEV_NAME,
268c2ecf20Sopenharmony_ci	},
278c2ecf20Sopenharmony_ci	{
288c2ecf20Sopenharmony_ci		.compatible = "st,lis3lv02dl-accel",
298c2ecf20Sopenharmony_ci		.data = LIS3LV02DL_ACCEL_DEV_NAME,
308c2ecf20Sopenharmony_ci	},
318c2ecf20Sopenharmony_ci	{
328c2ecf20Sopenharmony_ci		.compatible = "st,lsm303dlh-accel",
338c2ecf20Sopenharmony_ci		.data = LSM303DLH_ACCEL_DEV_NAME,
348c2ecf20Sopenharmony_ci	},
358c2ecf20Sopenharmony_ci	{
368c2ecf20Sopenharmony_ci		.compatible = "st,lsm303dlhc-accel",
378c2ecf20Sopenharmony_ci		.data = LSM303DLHC_ACCEL_DEV_NAME,
388c2ecf20Sopenharmony_ci	},
398c2ecf20Sopenharmony_ci	{
408c2ecf20Sopenharmony_ci		.compatible = "st,lis3dh-accel",
418c2ecf20Sopenharmony_ci		.data = LIS3DH_ACCEL_DEV_NAME,
428c2ecf20Sopenharmony_ci	},
438c2ecf20Sopenharmony_ci	{
448c2ecf20Sopenharmony_ci		.compatible = "st,lsm330d-accel",
458c2ecf20Sopenharmony_ci		.data = LSM330D_ACCEL_DEV_NAME,
468c2ecf20Sopenharmony_ci	},
478c2ecf20Sopenharmony_ci	{
488c2ecf20Sopenharmony_ci		.compatible = "st,lsm330dl-accel",
498c2ecf20Sopenharmony_ci		.data = LSM330DL_ACCEL_DEV_NAME,
508c2ecf20Sopenharmony_ci	},
518c2ecf20Sopenharmony_ci	{
528c2ecf20Sopenharmony_ci		.compatible = "st,lsm330dlc-accel",
538c2ecf20Sopenharmony_ci		.data = LSM330DLC_ACCEL_DEV_NAME,
548c2ecf20Sopenharmony_ci	},
558c2ecf20Sopenharmony_ci	{
568c2ecf20Sopenharmony_ci		.compatible = "st,lis331dl-accel",
578c2ecf20Sopenharmony_ci		.data = LIS331DL_ACCEL_DEV_NAME,
588c2ecf20Sopenharmony_ci	},
598c2ecf20Sopenharmony_ci	{
608c2ecf20Sopenharmony_ci		.compatible = "st,lis331dlh-accel",
618c2ecf20Sopenharmony_ci		.data = LIS331DLH_ACCEL_DEV_NAME,
628c2ecf20Sopenharmony_ci	},
638c2ecf20Sopenharmony_ci	{
648c2ecf20Sopenharmony_ci		.compatible = "st,lsm303dl-accel",
658c2ecf20Sopenharmony_ci		.data = LSM303DL_ACCEL_DEV_NAME,
668c2ecf20Sopenharmony_ci	},
678c2ecf20Sopenharmony_ci	{
688c2ecf20Sopenharmony_ci		.compatible = "st,lsm303dlm-accel",
698c2ecf20Sopenharmony_ci		.data = LSM303DLM_ACCEL_DEV_NAME,
708c2ecf20Sopenharmony_ci	},
718c2ecf20Sopenharmony_ci	{
728c2ecf20Sopenharmony_ci		.compatible = "st,lsm330-accel",
738c2ecf20Sopenharmony_ci		.data = LSM330_ACCEL_DEV_NAME,
748c2ecf20Sopenharmony_ci	},
758c2ecf20Sopenharmony_ci	{
768c2ecf20Sopenharmony_ci		.compatible = "st,lsm303agr-accel",
778c2ecf20Sopenharmony_ci		.data = LSM303AGR_ACCEL_DEV_NAME,
788c2ecf20Sopenharmony_ci	},
798c2ecf20Sopenharmony_ci	{
808c2ecf20Sopenharmony_ci		.compatible = "st,lis2dh12-accel",
818c2ecf20Sopenharmony_ci		.data = LIS2DH12_ACCEL_DEV_NAME,
828c2ecf20Sopenharmony_ci	},
838c2ecf20Sopenharmony_ci	{
848c2ecf20Sopenharmony_ci		.compatible = "st,h3lis331dl-accel",
858c2ecf20Sopenharmony_ci		.data = H3LIS331DL_ACCEL_DEV_NAME,
868c2ecf20Sopenharmony_ci	},
878c2ecf20Sopenharmony_ci	{
888c2ecf20Sopenharmony_ci		.compatible = "st,lis3l02dq",
898c2ecf20Sopenharmony_ci		.data = LIS3L02DQ_ACCEL_DEV_NAME,
908c2ecf20Sopenharmony_ci	},
918c2ecf20Sopenharmony_ci	{
928c2ecf20Sopenharmony_ci		.compatible = "st,lng2dm-accel",
938c2ecf20Sopenharmony_ci		.data = LNG2DM_ACCEL_DEV_NAME,
948c2ecf20Sopenharmony_ci	},
958c2ecf20Sopenharmony_ci	{
968c2ecf20Sopenharmony_ci		.compatible = "st,lis2dw12",
978c2ecf20Sopenharmony_ci		.data = LIS2DW12_ACCEL_DEV_NAME,
988c2ecf20Sopenharmony_ci	},
998c2ecf20Sopenharmony_ci	{
1008c2ecf20Sopenharmony_ci		.compatible = "st,lis3de",
1018c2ecf20Sopenharmony_ci		.data = LIS3DE_ACCEL_DEV_NAME,
1028c2ecf20Sopenharmony_ci	},
1038c2ecf20Sopenharmony_ci	{
1048c2ecf20Sopenharmony_ci		.compatible = "st,lis2de12",
1058c2ecf20Sopenharmony_ci		.data = LIS2DE12_ACCEL_DEV_NAME,
1068c2ecf20Sopenharmony_ci	},
1078c2ecf20Sopenharmony_ci	{
1088c2ecf20Sopenharmony_ci		.compatible = "st,lis2hh12",
1098c2ecf20Sopenharmony_ci		.data = LIS2HH12_ACCEL_DEV_NAME,
1108c2ecf20Sopenharmony_ci	},
1118c2ecf20Sopenharmony_ci	{},
1128c2ecf20Sopenharmony_ci};
1138c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, st_accel_of_match);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
1168c2ecf20Sopenharmony_cistatic const struct acpi_device_id st_accel_acpi_match[] = {
1178c2ecf20Sopenharmony_ci	{"SMO8840", (kernel_ulong_t)LIS2DH12_ACCEL_DEV_NAME},
1188c2ecf20Sopenharmony_ci	{"SMO8A90", (kernel_ulong_t)LNG2DM_ACCEL_DEV_NAME},
1198c2ecf20Sopenharmony_ci	{ },
1208c2ecf20Sopenharmony_ci};
1218c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, st_accel_acpi_match);
1228c2ecf20Sopenharmony_ci#endif
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic const struct i2c_device_id st_accel_id_table[] = {
1258c2ecf20Sopenharmony_ci	{ LSM303DLH_ACCEL_DEV_NAME },
1268c2ecf20Sopenharmony_ci	{ LSM303DLHC_ACCEL_DEV_NAME },
1278c2ecf20Sopenharmony_ci	{ LIS3DH_ACCEL_DEV_NAME },
1288c2ecf20Sopenharmony_ci	{ LSM330D_ACCEL_DEV_NAME },
1298c2ecf20Sopenharmony_ci	{ LSM330DL_ACCEL_DEV_NAME },
1308c2ecf20Sopenharmony_ci	{ LSM330DLC_ACCEL_DEV_NAME },
1318c2ecf20Sopenharmony_ci	{ LIS331DLH_ACCEL_DEV_NAME },
1328c2ecf20Sopenharmony_ci	{ LSM303DL_ACCEL_DEV_NAME },
1338c2ecf20Sopenharmony_ci	{ LSM303DLM_ACCEL_DEV_NAME },
1348c2ecf20Sopenharmony_ci	{ LSM330_ACCEL_DEV_NAME },
1358c2ecf20Sopenharmony_ci	{ LSM303AGR_ACCEL_DEV_NAME },
1368c2ecf20Sopenharmony_ci	{ LIS2DH12_ACCEL_DEV_NAME },
1378c2ecf20Sopenharmony_ci	{ LIS3L02DQ_ACCEL_DEV_NAME },
1388c2ecf20Sopenharmony_ci	{ LNG2DM_ACCEL_DEV_NAME },
1398c2ecf20Sopenharmony_ci	{ H3LIS331DL_ACCEL_DEV_NAME },
1408c2ecf20Sopenharmony_ci	{ LIS331DL_ACCEL_DEV_NAME },
1418c2ecf20Sopenharmony_ci	{ LIS3LV02DL_ACCEL_DEV_NAME },
1428c2ecf20Sopenharmony_ci	{ LIS2DW12_ACCEL_DEV_NAME },
1438c2ecf20Sopenharmony_ci	{ LIS3DE_ACCEL_DEV_NAME },
1448c2ecf20Sopenharmony_ci	{ LIS2DE12_ACCEL_DEV_NAME },
1458c2ecf20Sopenharmony_ci	{ LIS2HH12_ACCEL_DEV_NAME },
1468c2ecf20Sopenharmony_ci	{},
1478c2ecf20Sopenharmony_ci};
1488c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, st_accel_id_table);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic int st_accel_i2c_probe(struct i2c_client *client)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	const struct st_sensor_settings *settings;
1538c2ecf20Sopenharmony_ci	struct st_sensor_data *adata;
1548c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev;
1558c2ecf20Sopenharmony_ci	int ret;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	st_sensors_dev_name_probe(&client->dev, client->name, sizeof(client->name));
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	settings = st_accel_get_settings(client->name);
1608c2ecf20Sopenharmony_ci	if (!settings) {
1618c2ecf20Sopenharmony_ci		dev_err(&client->dev, "device name %s not recognized.\n",
1628c2ecf20Sopenharmony_ci			client->name);
1638c2ecf20Sopenharmony_ci		return -ENODEV;
1648c2ecf20Sopenharmony_ci	}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*adata));
1678c2ecf20Sopenharmony_ci	if (!indio_dev)
1688c2ecf20Sopenharmony_ci		return -ENOMEM;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	adata = iio_priv(indio_dev);
1718c2ecf20Sopenharmony_ci	adata->sensor_settings = (struct st_sensor_settings *)settings;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	ret = st_sensors_i2c_configure(indio_dev, client);
1748c2ecf20Sopenharmony_ci	if (ret < 0)
1758c2ecf20Sopenharmony_ci		return ret;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	ret = st_sensors_power_enable(indio_dev);
1788c2ecf20Sopenharmony_ci	if (ret)
1798c2ecf20Sopenharmony_ci		return ret;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	ret = st_accel_common_probe(indio_dev);
1828c2ecf20Sopenharmony_ci	if (ret < 0)
1838c2ecf20Sopenharmony_ci		goto st_accel_power_off;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	return 0;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cist_accel_power_off:
1888c2ecf20Sopenharmony_ci	st_sensors_power_disable(indio_dev);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	return ret;
1918c2ecf20Sopenharmony_ci}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_cistatic int st_accel_i2c_remove(struct i2c_client *client)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev = i2c_get_clientdata(client);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	st_accel_common_remove(indio_dev);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	st_sensors_power_disable(indio_dev);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	return 0;
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic struct i2c_driver st_accel_driver = {
2058c2ecf20Sopenharmony_ci	.driver = {
2068c2ecf20Sopenharmony_ci		.name = "st-accel-i2c",
2078c2ecf20Sopenharmony_ci		.of_match_table = st_accel_of_match,
2088c2ecf20Sopenharmony_ci		.acpi_match_table = ACPI_PTR(st_accel_acpi_match),
2098c2ecf20Sopenharmony_ci	},
2108c2ecf20Sopenharmony_ci	.probe_new = st_accel_i2c_probe,
2118c2ecf20Sopenharmony_ci	.remove = st_accel_i2c_remove,
2128c2ecf20Sopenharmony_ci	.id_table = st_accel_id_table,
2138c2ecf20Sopenharmony_ci};
2148c2ecf20Sopenharmony_cimodule_i2c_driver(st_accel_driver);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ciMODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
2178c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("STMicroelectronics accelerometers i2c driver");
2188c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
219