mirror of
https://github.com/Fishwaldo/build.git
synced 2025-03-23 15:21:39 +00:00
1991 lines
51 KiB
Diff
1991 lines
51 KiB
Diff
From 9d43538162796100f16026a6ee26d826dd82320f Mon Sep 17 00:00:00 2001
|
|
From: wwd <ericrock@foxmail.com>
|
|
Date: Mon, 16 May 2016 13:20:02 +0800
|
|
Subject: [PATCH] matrix: support Matrix starter kit
|
|
|
|
---
|
|
arch/arm/configs/sun8iw7p1smp_defconfig | 204 +++++++++++-
|
|
arch/arm/mach-sunxi/sun8i.c | 55 ++++
|
|
drivers/char/Kconfig | 24 ++
|
|
drivers/char/Makefile | 5 +
|
|
drivers/char/matrix_gpio_int.c | 309 +++++++++++++++++
|
|
drivers/char/matrix_hcsr04.c | 184 +++++++++++
|
|
drivers/char/matrix_pwm.c | 206 ++++++++++++
|
|
drivers/char/matrix_rotary_encoder.c | 205 ++++++++++++
|
|
drivers/input/misc/adxl34x.c | 33 +-
|
|
drivers/staging/iio/Kconfig | 1 +
|
|
drivers/staging/iio/Makefile | 1 +
|
|
drivers/staging/iio/humidity/Kconfig | 15 +
|
|
drivers/staging/iio/humidity/Makefile | 5 +
|
|
drivers/staging/iio/humidity/dht11.c | 366 +++++++++++++++++++++
|
|
drivers/staging/iio/industrialio-core.c | 1 +
|
|
drivers/staging/iio/types.h | 1 +
|
|
drivers/w1/masters/Makefile | 2 +-
|
|
drivers/w1/masters/w1-gpio-board.c | 59 ++++
|
|
drivers/w1/masters/w1-gpio.c | 13 +-
|
|
.../sun8iw7p1/configs/nanopi-h3/sys_config.fex | 9 +-
|
|
21 files changed, 1684 insertions(+), 28 deletions(-)
|
|
create mode 100644 drivers/char/matrix_gpio_int.c
|
|
create mode 100644 drivers/char/matrix_hcsr04.c
|
|
create mode 100644 drivers/char/matrix_pwm.c
|
|
create mode 100644 drivers/char/matrix_rotary_encoder.c
|
|
create mode 100644 drivers/staging/iio/humidity/Kconfig
|
|
create mode 100644 drivers/staging/iio/humidity/Makefile
|
|
create mode 100644 drivers/staging/iio/humidity/dht11.c
|
|
create mode 100644 drivers/w1/masters/w1-gpio-board.c
|
|
|
|
diff --git a/arch/arm/configs/sun8iw7p1smp_defconfig b/arch/arm/configs/sun8iw7p1smp_defconfig
|
|
index bc86f3d..8cec706 100644
|
|
--- a/arch/arm/configs/sun8iw7p1smp_defconfig
|
|
+++ b/arch/arm/configs/sun8iw7p1smp_defconfig
|
|
@@ -1079,7 +1079,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=y
|
|
# CONFIG_DS1682 is not set
|
|
# CONFIG_TI_DAC7512 is not set
|
|
CONFIG_UID_STAT=y
|
|
-# CONFIG_BMP085 is not set
|
|
+CONFIG_BMP085=m
|
|
# CONFIG_USB_SWITCH_FSA9480 is not set
|
|
# CONFIG_SUNXI_BROM_READ is not set
|
|
# CONFIG_C2PORT is not set
|
|
@@ -1396,7 +1396,9 @@ CONFIG_INPUT_UINPUT=y
|
|
# CONFIG_INPUT_GPIO is not set
|
|
# CONFIG_INPUT_PCF8574 is not set
|
|
# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
|
|
-# CONFIG_INPUT_ADXL34X is not set
|
|
+CONFIG_INPUT_ADXL34X=m
|
|
+CONFIG_INPUT_ADXL34X_I2C=m
|
|
+# CONFIG_INPUT_ADXL34X_SPI is not set
|
|
# CONFIG_INPUT_CMA3000 is not set
|
|
# CONFIG_INPUT_SHAFT_ENCODER is not set
|
|
|
|
@@ -1461,6 +1463,10 @@ CONFIG_SERIAL_SUNXI_CONSOLE=y
|
|
# CONFIG_DCC_TTY is not set
|
|
# CONFIG_RAMOOPS is not set
|
|
# CONFIG_SUNXI_D7S is not set
|
|
+CONFIG_MATRIX_GPIO_INT=m
|
|
+CONFIG_MATRIX_PWM=m
|
|
+CONFIG_MATRIX_ROTARY_ENCODER=m
|
|
+CONFIG_MATRIX_HCSR04=m
|
|
# CONFIG_IR_CUT is not set
|
|
CONFIG_SUNXI_CMATESET=y
|
|
# CONFIG_SUNXI_ARISC_TEST is not set
|
|
@@ -1475,7 +1481,7 @@ CONFIG_SUNXI_SOC_INFO=y
|
|
CONFIG_I2C=y
|
|
CONFIG_I2C_BOARDINFO=y
|
|
CONFIG_I2C_COMPAT=y
|
|
-# CONFIG_I2C_CHARDEV is not set
|
|
+CONFIG_I2C_CHARDEV=y
|
|
# CONFIG_I2C_MUX is not set
|
|
CONFIG_I2C_HELPER_AUTO=y
|
|
CONFIG_I2C_ALGOBIT=y
|
|
@@ -1530,7 +1536,7 @@ CONFIG_SPI_SUNXI=y
|
|
#
|
|
# SPI Protocol Masters
|
|
#
|
|
-# CONFIG_SPI_SPIDEV is not set
|
|
+CONFIG_SPI_SPIDEV=y
|
|
# CONFIG_SPI_TLE62X0 is not set
|
|
# CONFIG_HSI is not set
|
|
|
|
@@ -1602,7 +1608,29 @@ CONFIG_GPIO_SYSFS=y
|
|
# MODULbus GPIO expanders:
|
|
#
|
|
CONFIG_GPIO_SUNXI=m
|
|
-# CONFIG_W1 is not set
|
|
+CONFIG_W1=y
|
|
+
|
|
+#
|
|
+# 1-wire Bus Masters
|
|
+#
|
|
+# CONFIG_W1_MASTER_DS2490 is not set
|
|
+# CONFIG_W1_MASTER_DS2482 is not set
|
|
+# CONFIG_W1_MASTER_DS1WM is not set
|
|
+CONFIG_W1_MASTER_GPIO=m
|
|
+
|
|
+#
|
|
+# 1-wire Slaves
|
|
+#
|
|
+CONFIG_W1_SLAVE_THERM=y
|
|
+# CONFIG_W1_SLAVE_SMEM is not set
|
|
+# CONFIG_W1_SLAVE_DS2408 is not set
|
|
+# CONFIG_W1_SLAVE_DS2423 is not set
|
|
+# CONFIG_W1_SLAVE_DS2431 is not set
|
|
+# CONFIG_W1_SLAVE_DS2433 is not set
|
|
+# CONFIG_W1_SLAVE_DS2760 is not set
|
|
+# CONFIG_W1_SLAVE_DS2780 is not set
|
|
+# CONFIG_W1_SLAVE_DS2781 is not set
|
|
+# CONFIG_W1_SLAVE_BQ27000 is not set
|
|
# CONFIG_POWER_SUPPLY is not set
|
|
CONFIG_HWMON=y
|
|
# CONFIG_HWMON_VID is not set
|
|
@@ -1677,7 +1705,7 @@ CONFIG_HWMON=y
|
|
# CONFIG_SENSORS_NTC_THERMISTOR is not set
|
|
# CONFIG_SENSORS_PC87360 is not set
|
|
# CONFIG_SENSORS_PC87427 is not set
|
|
-# CONFIG_SENSORS_PCF8591 is not set
|
|
+CONFIG_SENSORS_PCF8591=m
|
|
# CONFIG_PMBUS is not set
|
|
# CONFIG_DA380 is not set
|
|
# CONFIG_SENSORS_SHT15 is not set
|
|
@@ -1809,7 +1837,8 @@ CONFIG_BCMA_POSSIBLE=y
|
|
# CONFIG_MFD_AAT2870_CORE is not set
|
|
# CONFIG_MFD_RC5T583 is not set
|
|
# CONFIG_REGULATOR is not set
|
|
-# CONFIG_PWM is not set
|
|
+CONFIG_PWM=y
|
|
+CONFIG_PWM_SUNXI=y
|
|
CONFIG_MEDIA_SUPPORT=y
|
|
|
|
#
|
|
@@ -2574,7 +2603,7 @@ CONFIG_RTC_INTF_DEV=y
|
|
#
|
|
# I2C RTC drivers
|
|
#
|
|
-# CONFIG_RTC_DRV_DS1307 is not set
|
|
+CONFIG_RTC_DRV_DS1307=m
|
|
# CONFIG_RTC_DRV_DS1374 is not set
|
|
# CONFIG_RTC_DRV_DS1672 is not set
|
|
# CONFIG_RTC_DRV_DS3232 is not set
|
|
@@ -2658,7 +2687,164 @@ CONFIG_SUNXI_DMA=y
|
|
#
|
|
# Microsoft Hyper-V guest support
|
|
#
|
|
-# CONFIG_STAGING is not set
|
|
+CONFIG_STAGING=y
|
|
+# CONFIG_USBIP_CORE is not set
|
|
+# CONFIG_ECHO is not set
|
|
+# CONFIG_ASUS_OLED is not set
|
|
+# CONFIG_RTLLIB is not set
|
|
+# CONFIG_R8712U is not set
|
|
+# CONFIG_RTS5139 is not set
|
|
+# CONFIG_TRANZPORT is not set
|
|
+# CONFIG_LINE6_USB is not set
|
|
+# CONFIG_USB_SERIAL_QUATECH2 is not set
|
|
+# CONFIG_USB_SERIAL_QUATECH_USB2 is not set
|
|
+# CONFIG_VT6656 is not set
|
|
+CONFIG_IIO=y
|
|
+# CONFIG_IIO_ST_HWMON is not set
|
|
+# CONFIG_IIO_BUFFER is not set
|
|
+# CONFIG_IIO_TRIGGER is not set
|
|
+
|
|
+#
|
|
+# Accelerometers
|
|
+#
|
|
+# CONFIG_ADIS16201 is not set
|
|
+# CONFIG_ADIS16203 is not set
|
|
+# CONFIG_ADIS16204 is not set
|
|
+# CONFIG_ADIS16209 is not set
|
|
+# CONFIG_ADIS16220 is not set
|
|
+# CONFIG_ADIS16240 is not set
|
|
+# CONFIG_KXSD9 is not set
|
|
+# CONFIG_LIS3L02DQ is not set
|
|
+
|
|
+#
|
|
+# Analog to digital converters
|
|
+#
|
|
+# CONFIG_AD7291 is not set
|
|
+# CONFIG_AD7298 is not set
|
|
+# CONFIG_AD7606 is not set
|
|
+# CONFIG_AD799X is not set
|
|
+# CONFIG_AD7476 is not set
|
|
+# CONFIG_AD7887 is not set
|
|
+# CONFIG_AD7780 is not set
|
|
+# CONFIG_AD7793 is not set
|
|
+# CONFIG_AD7816 is not set
|
|
+# CONFIG_AD7192 is not set
|
|
+# CONFIG_ADT7310 is not set
|
|
+# CONFIG_ADT7410 is not set
|
|
+# CONFIG_AD7280 is not set
|
|
+# CONFIG_MAX1363 is not set
|
|
+
|
|
+#
|
|
+# Analog digital bi-direction converters
|
|
+#
|
|
+# CONFIG_ADT7316 is not set
|
|
+
|
|
+#
|
|
+# Capacitance to digital converters
|
|
+#
|
|
+# CONFIG_AD7150 is not set
|
|
+# CONFIG_AD7152 is not set
|
|
+# CONFIG_AD7746 is not set
|
|
+
|
|
+#
|
|
+# Digital to analog converters
|
|
+#
|
|
+# CONFIG_AD5064 is not set
|
|
+# CONFIG_AD5360 is not set
|
|
+# CONFIG_AD5380 is not set
|
|
+# CONFIG_AD5421 is not set
|
|
+# CONFIG_AD5624R_SPI is not set
|
|
+# CONFIG_AD5446 is not set
|
|
+# CONFIG_AD5504 is not set
|
|
+# CONFIG_AD5764 is not set
|
|
+# CONFIG_AD5791 is not set
|
|
+# CONFIG_AD5686 is not set
|
|
+# CONFIG_MAX517 is not set
|
|
+
|
|
+#
|
|
+# Direct Digital Synthesis
|
|
+#
|
|
+# CONFIG_AD5930 is not set
|
|
+# CONFIG_AD9832 is not set
|
|
+# CONFIG_AD9834 is not set
|
|
+# CONFIG_AD9850 is not set
|
|
+# CONFIG_AD9852 is not set
|
|
+# CONFIG_AD9910 is not set
|
|
+# CONFIG_AD9951 is not set
|
|
+
|
|
+#
|
|
+# Digital gyroscope sensors
|
|
+#
|
|
+# CONFIG_ADIS16060 is not set
|
|
+# CONFIG_ADIS16080 is not set
|
|
+# CONFIG_ADIS16130 is not set
|
|
+# CONFIG_ADIS16260 is not set
|
|
+# CONFIG_ADXRS450 is not set
|
|
+
|
|
+#
|
|
+# Humidity sensors
|
|
+#
|
|
+CONFIG_DHT11=m
|
|
+
|
|
+#
|
|
+# Network Analyzer, Impedance Converters
|
|
+#
|
|
+# CONFIG_AD5933 is not set
|
|
+CONFIG_INV_SENSOR=y
|
|
+
|
|
+#
|
|
+# Light sensors
|
|
+#
|
|
+# CONFIG_SENSORS_ISL29018 is not set
|
|
+# CONFIG_SENSORS_TSL2563 is not set
|
|
+# CONFIG_TSL2583 is not set
|
|
+
|
|
+#
|
|
+# Magnetometer sensors
|
|
+#
|
|
+# CONFIG_SENSORS_HMC5843 is not set
|
|
+
|
|
+#
|
|
+# Active energy metering IC
|
|
+#
|
|
+# CONFIG_ADE7753 is not set
|
|
+# CONFIG_ADE7754 is not set
|
|
+# CONFIG_ADE7758 is not set
|
|
+# CONFIG_ADE7759 is not set
|
|
+# CONFIG_ADE7854 is not set
|
|
+
|
|
+#
|
|
+# Resolver to digital converters
|
|
+#
|
|
+# CONFIG_AD2S90 is not set
|
|
+# CONFIG_AD2S1200 is not set
|
|
+# CONFIG_AD2S1210 is not set
|
|
+
|
|
+#
|
|
+# Triggers - standalone
|
|
+#
|
|
+# CONFIG_IIO_SIMPLE_DUMMY is not set
|
|
+# CONFIG_ZSMALLOC is not set
|
|
+# CONFIG_FB_SM7XX is not set
|
|
+# CONFIG_USB_ENESTORAGE is not set
|
|
+# CONFIG_BCM_WIMAX is not set
|
|
+# CONFIG_FT1000 is not set
|
|
+
|
|
+#
|
|
+# Speakup console speech
|
|
+#
|
|
+# CONFIG_SPEAKUP is not set
|
|
+# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set
|
|
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set
|
|
+# CONFIG_STAGING_MEDIA is not set
|
|
+
|
|
+#
|
|
+# Android
|
|
+#
|
|
+# CONFIG_ANDROID is not set
|
|
+# CONFIG_PHONE is not set
|
|
+# CONFIG_USB_WPAN_HCD is not set
|
|
+# CONFIG_SUNXIOOPS is not set
|
|
CONFIG_CLKDEV_LOOKUP=y
|
|
CONFIG_HAVE_CLK_PREPARE=y
|
|
CONFIG_COMMON_CLK=y
|
|
diff --git a/arch/arm/mach-sunxi/sun8i.c b/arch/arm/mach-sunxi/sun8i.c
|
|
index 2c35075..7700d04 100755
|
|
--- a/arch/arm/mach-sunxi/sun8i.c
|
|
+++ b/arch/arm/mach-sunxi/sun8i.c
|
|
@@ -117,6 +117,40 @@ static struct i2c_board_info i2c_ina219_devs[] __initdata = {
|
|
};
|
|
#endif
|
|
|
|
+/*------------------------------------------------------------------------------
|
|
+ * Matrix device
|
|
+ */
|
|
+#if defined(CONFIG_INPUT_ADXL34X_I2C_MODULE)
|
|
+#define ADXL34X_I2C_BUS (0)
|
|
+static struct i2c_board_info __initdata adxl34x_i2c_bdi = {
|
|
+ I2C_BOARD_INFO("adxl34x", 0x1d),
|
|
+ .irq = -1,
|
|
+};
|
|
+#endif
|
|
+
|
|
+#if defined(CONFIG_BMP085_MODULE)
|
|
+#define BMP085_I2C_BUS (0)
|
|
+static struct i2c_board_info __initdata bmp085_i2c_bdi = {
|
|
+ I2C_BOARD_INFO("bmp085", 0x77),
|
|
+ .irq = -1,
|
|
+};
|
|
+#endif
|
|
+
|
|
+#if defined(CONFIG_RTC_DRV_DS1307_MODULE)
|
|
+#define DS1307_I2C_BUS (0)
|
|
+static struct i2c_board_info __initdata ds1307_i2c_bdi = {
|
|
+ I2C_BOARD_INFO("ds1307", 0X68),
|
|
+ .irq = -1,
|
|
+};
|
|
+#endif
|
|
+
|
|
+#if defined(CONFIG_SENSORS_PCF8591_MODULE)
|
|
+#define PCF8591_I2C_BUS (0)
|
|
+static struct i2c_board_info __initdata pcf8591_i2c_bdi = {
|
|
+ I2C_BOARD_INFO("pcf8591", 0x48),
|
|
+};
|
|
+#endif
|
|
+
|
|
#if defined(CONFIG_ION) || defined(CONFIG_ION_MODULE)
|
|
#define DEFAULT_SUNXI_ION_RESERVE_SIZE 96
|
|
#define ION_CARVEOUT_INIT_MAX 4
|
|
@@ -461,6 +495,27 @@ static void __init sunxi_dev_init(void)
|
|
}
|
|
printk("ina219 device registered\n");
|
|
#endif
|
|
+
|
|
+#if defined(CONFIG_INPUT_ADXL34X_I2C_MODULE)
|
|
+ printk("plat: add adxl34x device\n");
|
|
+ i2c_register_board_info(ADXL34X_I2C_BUS, &adxl34x_i2c_bdi, 1);
|
|
+#endif
|
|
+
|
|
+#if defined(CONFIG_BMP085_MODULE)
|
|
+ printk("plat: add bmp085 device\n");
|
|
+ i2c_register_board_info(BMP085_I2C_BUS, &bmp085_i2c_bdi, 1);
|
|
+#endif
|
|
+
|
|
+#if defined(CONFIG_RTC_DRV_DS1307_MODULE)
|
|
+ printk("plat: add ds1307 device\n");
|
|
+ i2c_register_board_info(DS1307_I2C_BUS, &ds1307_i2c_bdi, 1);
|
|
+#endif
|
|
+
|
|
+#if defined(CONFIG_SENSORS_PCF8591_MODULE)
|
|
+ printk("plat: add pcf8591 device\n");
|
|
+ i2c_register_board_info(PCF8591_I2C_BUS, &pcf8591_i2c_bdi, 1);
|
|
+#endif
|
|
+
|
|
#ifdef CONFIG_ANDROID_RAM_CONSOLE
|
|
/* ram console platform device initialize*/
|
|
ram_console_device_init();
|
|
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
|
|
index 6614788..5090528 100755
|
|
--- a/drivers/char/Kconfig
|
|
+++ b/drivers/char/Kconfig
|
|
@@ -636,6 +636,30 @@ config SUNXI_D7S
|
|
---help---
|
|
Sunxi display 7 segment for h3.
|
|
|
|
+config MATRIX_GPIO_INT
|
|
+ tristate "Matrix GPIO int sensor module"
|
|
+ default m
|
|
+ ---help---
|
|
+ Driver for Matrix GPIO int sensor module.
|
|
+
|
|
+config MATRIX_PWM
|
|
+ tristate "Matrix PWM module"
|
|
+ default m
|
|
+ ---help---
|
|
+ Driver for Matrix PWM module.
|
|
+
|
|
+config MATRIX_ROTARY_ENCODER
|
|
+ tristate "Matrix rotary encoder"
|
|
+ default m
|
|
+ ---help---
|
|
+ Driver for Matrix rotary encoder.
|
|
+
|
|
+config MATRIX_HCSR04
|
|
+ tristate "Matrix hcsr04"
|
|
+ default m
|
|
+ ---help---
|
|
+ Driver for Matrix hcsr04.
|
|
+
|
|
source "drivers/char/sunxi_g2d/Kconfig"
|
|
source "drivers/char/sunxi_ir_cut/Kconfig"
|
|
source "drivers/char/cma_test/Kconfig"
|
|
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
|
|
index 399be2b..f0bda58 100755
|
|
--- a/drivers/char/Makefile
|
|
+++ b/drivers/char/Makefile
|
|
@@ -82,3 +82,8 @@ obj-y += sunxi-di/
|
|
obj-${CONFIG_ID} += sunxi_id/
|
|
obj-${CONFIG_RESET_KEY} += sunxi_key/
|
|
obj-$(CONFIG_IR_CUT) += sunxi_ir_cut/
|
|
+
|
|
+obj-$(CONFIG_MATRIX_GPIO_INT) += matrix_gpio_int.o
|
|
+obj-$(CONFIG_MATRIX_PWM) += matrix_pwm.o
|
|
+obj-$(CONFIG_MATRIX_ROTARY_ENCODER) += matrix_rotary_encoder.o
|
|
+obj-$(CONFIG_MATRIX_HCSR04) += matrix_hcsr04.o
|
|
\ No newline at end of file
|
|
diff --git a/drivers/char/matrix_gpio_int.c b/drivers/char/matrix_gpio_int.c
|
|
new file mode 100644
|
|
index 0000000..cbe29ca
|
|
--- /dev/null
|
|
+++ b/drivers/char/matrix_gpio_int.c
|
|
@@ -0,0 +1,309 @@
|
|
+#include <linux/module.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/poll.h>
|
|
+#include <linux/sched.h>
|
|
+#include <linux/irq.h>
|
|
+#include <asm/irq.h>
|
|
+#include <asm/io.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <asm/uaccess.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/cdev.h>
|
|
+#include <linux/miscdevice.h>
|
|
+#include <linux/gpio.h>
|
|
+
|
|
+#define DEVICE_NAME "sensor"
|
|
+#define MAX_SENDEV_NUM 8
|
|
+
|
|
+struct sensor {
|
|
+ int gpio;
|
|
+ int int_type;
|
|
+};
|
|
+
|
|
+
|
|
+struct sensor_desc {
|
|
+ int ID;
|
|
+ int gpio;
|
|
+ int int_type;
|
|
+ char *name;
|
|
+ int is_used;
|
|
+ struct timer_list timer;
|
|
+};
|
|
+
|
|
+static size_t sensor_num = -1; // number of sensor has been registered
|
|
+static int is_started = 0;
|
|
+static struct semaphore lock;
|
|
+
|
|
+static struct sensor_desc sensor_dev[MAX_SENDEV_NUM] = {
|
|
+ { 0, -1, -1, "gpio_int_sensor1"},
|
|
+ { 1, -1, -1, "gpio_int_sensor2"},
|
|
+ { 2, -1, -1, "gpio_int_sensor3"},
|
|
+ { 3, -1, -1, "gpio_int_sensor4"},
|
|
+ { 4, -1, -1, "gpio_int_sensor5"},
|
|
+ { 5, -1, -1, "gpio_int_sensor6"},
|
|
+ { 6, -1, -1, "gpio_int_sensor7"},
|
|
+ { 7, -1, -1, "gpio_int_sensor8"},
|
|
+};
|
|
+
|
|
+static volatile char sensor_dev_value[MAX_SENDEV_NUM] = {
|
|
+};
|
|
+
|
|
+static DECLARE_WAIT_QUEUE_HEAD(sensor_dev_waitq);
|
|
+
|
|
+static volatile int ev_press = 0;
|
|
+
|
|
+// static int timer_counter = 0;
|
|
+static void gpio_int_sensors_timer(unsigned long _data)
|
|
+{
|
|
+
|
|
+ struct sensor_desc *bdata = (struct sensor_desc *)_data;
|
|
+ int ID;
|
|
+ unsigned tmp = gpio_get_value(bdata->gpio);
|
|
+ ID = bdata->ID;
|
|
+
|
|
+ // printk("%s %d value=%d int_type=%d\n", __FUNCTION__, timer_counter++, tmp, bdata->int_type);
|
|
+ if (bdata->int_type == IRQ_TYPE_EDGE_RISING) {
|
|
+ if(tmp == 1) {
|
|
+ sensor_dev_value[ID] = 1;
|
|
+ ev_press = 1;
|
|
+ wake_up_interruptible(&sensor_dev_waitq);
|
|
+ }
|
|
+ } else if (bdata->int_type == IRQ_TYPE_EDGE_FALLING) {
|
|
+ if(tmp == 0) {
|
|
+ sensor_dev_value[ID] = 1;
|
|
+ ev_press = 1;
|
|
+ wake_up_interruptible(&sensor_dev_waitq);
|
|
+ }
|
|
+ } else if (bdata->int_type == IRQ_TYPE_EDGE_BOTH) {
|
|
+ sensor_dev_value[ID] = tmp;
|
|
+ ev_press = 1;
|
|
+ wake_up_interruptible(&sensor_dev_waitq);
|
|
+ }
|
|
+}
|
|
+
|
|
+// static int int_counter=0;
|
|
+static irqreturn_t gpio_int_sensor_interrupt(int irq, void *dev_id)
|
|
+{
|
|
+ // printk("%s %d\n", __FUNCTION__, int_counter++);
|
|
+ struct sensor_desc *bdata = (struct sensor_desc *)dev_id;
|
|
+ mod_timer(&bdata->timer, jiffies + msecs_to_jiffies(100));
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+static int start_all_sensor(void)
|
|
+{
|
|
+ int irq;
|
|
+ int i;
|
|
+ int err = 0;
|
|
+
|
|
+ for (i = 0; i < sensor_num; i++) {
|
|
+ if (!sensor_dev[i].gpio)
|
|
+ continue;
|
|
+
|
|
+ setup_timer(&sensor_dev[i].timer, gpio_int_sensors_timer,
|
|
+ (unsigned long)&sensor_dev[i]);
|
|
+
|
|
+ err = gpio_request(sensor_dev[i].gpio, "gpio_int_sensor");
|
|
+ if (err) {
|
|
+ printk("%s gpio_request %d fail\n", __FUNCTION__, sensor_dev[i].gpio);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ irq = gpio_to_irq(sensor_dev[i].gpio);
|
|
+ err = request_irq(irq, gpio_int_sensor_interrupt, IRQ_TYPE_EDGE_FALLING,
|
|
+ sensor_dev[i].name, (void *)&sensor_dev[i]);
|
|
+ if (err) {
|
|
+ printk("%s request_irq %d fail\n", __FUNCTION__, irq);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (err) {
|
|
+ i--;
|
|
+ for (; i >= 0; i--) {
|
|
+ if (!sensor_dev[i].gpio)
|
|
+ continue;
|
|
+
|
|
+ gpio_free(sensor_dev[i].gpio);
|
|
+ irq = gpio_to_irq(sensor_dev[i].gpio);
|
|
+ disable_irq(irq);
|
|
+ free_irq(irq, (void *)&sensor_dev[i]);
|
|
+
|
|
+ del_timer_sync(&sensor_dev[i].timer);
|
|
+ }
|
|
+
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
+ ev_press = 0;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int gpio_int_sensors_open(struct inode *inode, struct file *file)
|
|
+{
|
|
+ if (down_trylock(&lock))
|
|
+ return -EBUSY;
|
|
+ sensor_num = 0;
|
|
+ is_started = 0;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int stop_all_sensor(void)
|
|
+{
|
|
+ int irq, i;
|
|
+
|
|
+ for (i = 0; i < sensor_num; i++) {
|
|
+ if (!sensor_dev[i].gpio)
|
|
+ continue;
|
|
+
|
|
+ gpio_free(sensor_dev[i].gpio);
|
|
+ irq = gpio_to_irq(sensor_dev[i].gpio);
|
|
+ free_irq(irq, (void *)&sensor_dev[i]);
|
|
+
|
|
+ del_timer_sync(&sensor_dev[i].timer);
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int gpio_int_sensors_close(struct inode *inode, struct file *file)
|
|
+{
|
|
+ // printk("%s sensor_num=%d is_started=%d\n",__FUNCTION__, sensor_num, is_started);
|
|
+ if (is_started && sensor_num > 0) {
|
|
+ stop_all_sensor();
|
|
+ }
|
|
+ sensor_num = -1;
|
|
+ is_started = 0;
|
|
+ ev_press = 0;
|
|
+ up(&lock);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+// static int read_counter = 0;
|
|
+static int gpio_int_sensors_read(struct file *filp, char __user *buff,
|
|
+ size_t count, loff_t *offp)
|
|
+{
|
|
+ unsigned long err;
|
|
+ int i = 0;
|
|
+
|
|
+ if (!ev_press) {
|
|
+ if (filp->f_flags & O_NONBLOCK)
|
|
+ return -EAGAIN;
|
|
+ else
|
|
+ wait_event_interruptible(sensor_dev_waitq, ev_press);
|
|
+ }
|
|
+
|
|
+ ev_press = 0;
|
|
+
|
|
+ err = copy_to_user((void *)buff, (const void *)(&sensor_dev_value),
|
|
+ min(sensor_num, count));
|
|
+ for (i = 0; i<sensor_num; i++) {
|
|
+ sensor_dev_value[i] = 0;
|
|
+ }
|
|
+
|
|
+ return err ? -EFAULT : min(sensor_num, count);
|
|
+}
|
|
+
|
|
+static unsigned int gpio_int_sensors_poll( struct file *file,
|
|
+ struct poll_table_struct *wait)
|
|
+{
|
|
+ unsigned int mask = 0;
|
|
+
|
|
+ poll_wait(file, &sensor_dev_waitq, wait);
|
|
+ if (ev_press)
|
|
+ mask |= POLLIN | POLLRDNORM;
|
|
+
|
|
+ return mask;
|
|
+}
|
|
+
|
|
+static long gpio_int_sensors_ioctl(struct file *filp, unsigned int cmd,
|
|
+ unsigned long arg)
|
|
+{
|
|
+#define ADD_SENSOR (0)
|
|
+#define DEL_SENSOR (1)
|
|
+#define START_ALL_SENSOR (4)
|
|
+#define STOP_ALL_SENSOR (8)
|
|
+
|
|
+ struct sensor sen;
|
|
+ void __user *argp;
|
|
+ int del_dev;
|
|
+ int ret;
|
|
+
|
|
+ //printk("%s cmd=%d\n", __func__, cmd);
|
|
+ switch(cmd) {
|
|
+ case ADD_SENSOR:
|
|
+ if (is_started != 0 || sensor_num >= MAX_SENDEV_NUM)
|
|
+ return -EBUSY;
|
|
+ argp = (void __user *)arg;
|
|
+ if (copy_from_user(&sen, argp, sizeof sen))
|
|
+ return -EINVAL;
|
|
+ sensor_dev[sensor_num].gpio = sen.gpio;
|
|
+ sensor_dev[sensor_num].int_type= sen.int_type;
|
|
+ sensor_num++;
|
|
+ break;
|
|
+ case DEL_SENSOR:
|
|
+ del_dev = (int)arg;
|
|
+ // printk("%s del_dev=%d\n", __func__, del_dev);
|
|
+ if (is_started != 0 || sensor_num <= 0 || del_dev != sensor_num)
|
|
+ return -EINVAL;
|
|
+ sensor_dev[sensor_num].gpio = -1;
|
|
+ sensor_dev[sensor_num].int_type= -1;
|
|
+ sensor_num--;
|
|
+ break;
|
|
+ case START_ALL_SENSOR:
|
|
+ if (is_started != 0 || sensor_num <= 0)
|
|
+ return -EBUSY;
|
|
+ if((ret = start_all_sensor()) < 0)
|
|
+ return ret;
|
|
+ is_started = 1;
|
|
+ break;
|
|
+ case STOP_ALL_SENSOR:
|
|
+ if (is_started != 1 || sensor_num <= 0)
|
|
+ return -EBUSY;
|
|
+ stop_all_sensor();
|
|
+ is_started = 0;
|
|
+ break;
|
|
+ default:
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static struct file_operations dev_fops = {
|
|
+ .owner = THIS_MODULE,
|
|
+ .open = gpio_int_sensors_open,
|
|
+ .release = gpio_int_sensors_close,
|
|
+ .read = gpio_int_sensors_read,
|
|
+ .poll = gpio_int_sensors_poll,
|
|
+ .unlocked_ioctl = gpio_int_sensors_ioctl,
|
|
+};
|
|
+
|
|
+static struct miscdevice misc = {
|
|
+ .minor = MISC_DYNAMIC_MINOR,
|
|
+ .name = DEVICE_NAME,
|
|
+ .fops = &dev_fops,
|
|
+};
|
|
+
|
|
+static int __init sensor_dev_init(void)
|
|
+{
|
|
+ printk("Matirx GPIO Int sensor init\n");
|
|
+ sema_init(&lock, 1);
|
|
+ return misc_register(&misc);
|
|
+}
|
|
+
|
|
+static void __exit sensor_dev_exit(void)
|
|
+{
|
|
+ printk("Matirx GPIO Int sensor exit\n");
|
|
+ misc_deregister(&misc);
|
|
+}
|
|
+
|
|
+module_init(sensor_dev_init);
|
|
+module_exit(sensor_dev_exit);
|
|
+
|
|
+MODULE_LICENSE("GPL");
|
|
+MODULE_AUTHOR("FriendlyARM Inc.");
|
|
+
|
|
diff --git a/drivers/char/matrix_hcsr04.c b/drivers/char/matrix_hcsr04.c
|
|
new file mode 100644
|
|
index 0000000..3f4961b
|
|
--- /dev/null
|
|
+++ b/drivers/char/matrix_hcsr04.c
|
|
@@ -0,0 +1,184 @@
|
|
+#include <linux/module.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/moduleparam.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/hrtimer.h>
|
|
+#include <linux/ktime.h>
|
|
+#include <linux/device.h>
|
|
+#include <linux/kdev_t.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/sched.h>
|
|
+
|
|
+MODULE_LICENSE("Dual BSD/GPL");
|
|
+MODULE_AUTHOR("DA BAI");
|
|
+MODULE_DESCRIPTION("Driver for HC-SR04 ultrasonic sensor");
|
|
+
|
|
+// #define HCSR04_IRQ_DEUBG
|
|
+struct HCSR04_resource {
|
|
+ int pin;
|
|
+};
|
|
+
|
|
+static int HCSR04_PIN = -1;
|
|
+static int hasResource = 0;
|
|
+static int irq_num = 0;
|
|
+static int irq_time[3];
|
|
+static int valid_value = 0;
|
|
+static DECLARE_WAIT_QUEUE_HEAD(hcsr_waitq);
|
|
+
|
|
+static int hcsr04_hwexit(void);
|
|
+static int hcsr04_hwinit(void);
|
|
+static ssize_t hcsr04_value_read(struct class *class, struct class_attribute *attr, char *buf);
|
|
+static irqreturn_t gpio_isr(int irq, void *data);
|
|
+
|
|
+static ssize_t hcsr04_value_write(struct class *class, struct class_attribute *attr, const char *buf, size_t len)
|
|
+{
|
|
+ struct HCSR04_resource *res;
|
|
+ if (len == 4) {
|
|
+ res = (struct HCSR04_resource *)buf;
|
|
+
|
|
+ if (res->pin != -1 && hasResource == 0) {
|
|
+ HCSR04_PIN = res->pin;
|
|
+ if (hcsr04_hwinit() == -1) {
|
|
+ return -1;
|
|
+ }
|
|
+ hasResource = 1;
|
|
+ } else if (res->pin == -1 && hasResource == 1) {
|
|
+ if (hcsr04_hwexit() == -1) {
|
|
+ return -1;
|
|
+ }
|
|
+ hasResource = 0;
|
|
+ }
|
|
+ }
|
|
+ return len;
|
|
+}
|
|
+
|
|
+// This function is called when you read /sys/class/hcsr04/value
|
|
+static ssize_t hcsr04_value_read(struct class *class, struct class_attribute *attr, char *buf)
|
|
+{
|
|
+ int ret = -1;
|
|
+ int gpio_irq=-1;
|
|
+
|
|
+ if (hasResource == 0) {
|
|
+ return 0;
|
|
+ }
|
|
+ irq_num = 0;
|
|
+ valid_value = 0;
|
|
+ gpio_direction_output(HCSR04_PIN, 0);
|
|
+ udelay(50);
|
|
+ gpio_set_value(HCSR04_PIN, 1);
|
|
+ udelay(50);
|
|
+ gpio_set_value(HCSR04_PIN, 0);
|
|
+ udelay(50);
|
|
+
|
|
+ ret = gpio_to_irq(HCSR04_PIN);
|
|
+ if (ret < 0) {
|
|
+ printk(KERN_ERR"%s fail to gpio_to_irq\n", __func__);
|
|
+ goto fail;
|
|
+ } else {
|
|
+ gpio_irq = ret;
|
|
+ }
|
|
+
|
|
+ ret = request_irq(gpio_irq, gpio_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING , "hc-sr04", NULL);
|
|
+ if (ret) {
|
|
+ printk(KERN_ERR"%s fail to request_irq\n", __func__);
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ if(wait_event_interruptible_timeout(hcsr_waitq, valid_value, HZ) == 0) {
|
|
+ printk(KERN_ERR"%s timeout\n", __func__);
|
|
+ free_irq(gpio_irq, NULL);
|
|
+ goto fail;
|
|
+ }
|
|
+ free_irq(gpio_irq, NULL);
|
|
+#ifdef HCSR04_IRQ_DEUBG
|
|
+ printk("%s irq_time[1]=%d irq_time[0]=%d %d\n", __func__, irq_time[1], irq_time[0], irq_time[1]-irq_time[0]);
|
|
+#endif
|
|
+ return sprintf(buf, "%d\n", irq_time[1]-irq_time[0]);
|
|
+ fail:
|
|
+ return sprintf(buf, "%d\n", -1);;
|
|
+}
|
|
+
|
|
+// Sysfs definitions for hcsr04 class
|
|
+static struct class_attribute hcsr04_class_attrs[] = {
|
|
+ __ATTR(value, S_IRUGO | S_IWUSR, hcsr04_value_read, hcsr04_value_write),
|
|
+ __ATTR_NULL,
|
|
+};
|
|
+
|
|
+// Name of directory created in /sys/class
|
|
+static struct class hcsr04_class = {
|
|
+ .name = "hcsr04",
|
|
+ .owner = THIS_MODULE,
|
|
+ .class_attrs = hcsr04_class_attrs,
|
|
+};
|
|
+
|
|
+// Interrupt handler on ECHO signal
|
|
+static irqreturn_t gpio_isr(int irq, void *data)
|
|
+{
|
|
+ if (valid_value == 0) {
|
|
+ if((irq_num == 0 && gpio_get_value(HCSR04_PIN) != 1) ||
|
|
+ (irq_num == 1 && gpio_get_value(HCSR04_PIN) != 0) ||
|
|
+ (irq_num == 2 && gpio_get_value(HCSR04_PIN) != 1)
|
|
+ ) {
|
|
+ return IRQ_HANDLED;
|
|
+ }
|
|
+ irq_time[irq_num] = ktime_to_us(ktime_get());
|
|
+ if(irq_num == 2) {
|
|
+#ifdef HCSR04_IRQ_DEUBG
|
|
+ int i = 0;
|
|
+ for(i=0; i<3; i++)
|
|
+ printk("%d:%d\n", i, irq_time[i]);
|
|
+#endif
|
|
+ valid_value = 1;
|
|
+ wake_up_interruptible(&hcsr_waitq);
|
|
+ return IRQ_HANDLED;
|
|
+ }
|
|
+ irq_num++;
|
|
+ }
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+static int hcsr04_hwinit(void)
|
|
+{
|
|
+ int rtc;
|
|
+
|
|
+ rtc=gpio_request(HCSR04_PIN, "HCSR04");
|
|
+ if (rtc!=0) {
|
|
+ printk(KERN_INFO "Error %d\n",__LINE__);
|
|
+ goto fail;
|
|
+ }
|
|
+ return 0;
|
|
+
|
|
+ fail:
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static int hcsr04_init(void)
|
|
+{
|
|
+ printk(KERN_INFO "HC-SR04 driver v0.32 initializing.\n");
|
|
+
|
|
+ if (class_register(&hcsr04_class)<0)
|
|
+ goto fail;
|
|
+ return 0;
|
|
+
|
|
+ fail:
|
|
+ return -1;
|
|
+
|
|
+}
|
|
+
|
|
+static int hcsr04_hwexit(void)
|
|
+{
|
|
+ gpio_free(HCSR04_PIN);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void hcsr04_exit(void)
|
|
+{
|
|
+ class_unregister(&hcsr04_class);
|
|
+ printk(KERN_INFO "HC-SR04 disabled.\n");
|
|
+}
|
|
+
|
|
+module_init(hcsr04_init);
|
|
+module_exit(hcsr04_exit);
|
|
+
|
|
diff --git a/drivers/char/matrix_pwm.c b/drivers/char/matrix_pwm.c
|
|
new file mode 100644
|
|
index 0000000..5cdd951
|
|
--- /dev/null
|
|
+++ b/drivers/char/matrix_pwm.c
|
|
@@ -0,0 +1,206 @@
|
|
+/*
|
|
+ * linux/drivers/char/matrix_pwm.c
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
+ * published by the Free Software Foundation.
|
|
+ */
|
|
+
|
|
+#include <linux/module.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/backlight.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/pwm.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/miscdevice.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/gpio.h>
|
|
+
|
|
+#include <mach/platform.h>
|
|
+#include <asm/uaccess.h>
|
|
+
|
|
+#define DEVICE_NAME "pwm"
|
|
+#define PWM_NUM (2)
|
|
+#define PWM_IOCTL_SET_FREQ (0x1)
|
|
+#define PWM_IOCTL_STOP (0x0)
|
|
+#define NS_IN_1HZ (1000000000UL)
|
|
+
|
|
+static int is_pwm_working[PWM_NUM] = {0, 0};
|
|
+static struct pwm_device *matrix_pwm[PWM_NUM];
|
|
+static struct semaphore lock;
|
|
+
|
|
+static int pwm_set_freq(int index, int pin, unsigned long freq, int duty)
|
|
+{
|
|
+ int ret=0;
|
|
+ int period_ns = NS_IN_1HZ / freq;
|
|
+ int duty_ns = period_ns / 1000 * duty;
|
|
+
|
|
+ printk("%s %d %d\n", __func__, period_ns, duty_ns);
|
|
+ if ((ret = pwm_config(matrix_pwm[index], duty_ns, period_ns))) {
|
|
+ printk("fail to pwm_config\n");
|
|
+ return ret;
|
|
+ }
|
|
+ if ((ret = pwm_enable(matrix_pwm[index]))) {
|
|
+ printk("fail to pwm_enable\n");
|
|
+ return ret;
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void pwm_stop(int index, int pin)
|
|
+{
|
|
+ pwm_config(matrix_pwm[index], 0, NS_IN_1HZ / 100);
|
|
+ pwm_disable(matrix_pwm[index]);
|
|
+}
|
|
+
|
|
+static int matrix_pwm_hw_init(int index, int pin)
|
|
+{
|
|
+ int ret=0;
|
|
+
|
|
+#if 0
|
|
+ ret = gpio_request(pin, DEVICE_NAME);
|
|
+ if (ret) {
|
|
+ printk("request gpio %d for pwm failed\n", pin);
|
|
+ return ret;
|
|
+ }
|
|
+ gpio_direction_output(pin, 0);
|
|
+#endif
|
|
+
|
|
+ matrix_pwm[index] = pwm_request(index, DEVICE_NAME);
|
|
+ if (IS_ERR(matrix_pwm[index])) {
|
|
+ printk("request pwm%d failed\n", index);
|
|
+#if 0
|
|
+ gpio_free(pin);
|
|
+#endif
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ pwm_stop(index, pin);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void matrix_pwm_hw_exit(int index,int pin)
|
|
+{
|
|
+ pwm_stop(index, pin);
|
|
+ pwm_free(matrix_pwm[index]);
|
|
+#if 0
|
|
+ gpio_free(pin);
|
|
+#endif
|
|
+}
|
|
+
|
|
+static int matrix_pwm_open(struct inode *inode, struct file *file) {
|
|
+ if (!down_trylock(&lock))
|
|
+ return 0;
|
|
+ else
|
|
+ return -EBUSY;
|
|
+}
|
|
+
|
|
+static int matrix_pwm_close(struct inode *inode, struct file *file) {
|
|
+ up(&lock);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static long matrix_pwm_ioctl(struct file *filep, unsigned int cmd,unsigned long arg)
|
|
+{
|
|
+ int pwm_id;
|
|
+ int param[3];
|
|
+ int gpio;
|
|
+ int freq;
|
|
+ int duty;
|
|
+ int ret;
|
|
+
|
|
+ switch (cmd) {
|
|
+ case PWM_IOCTL_SET_FREQ:
|
|
+ if (copy_from_user(param, (void __user *)arg, sizeof(param)))
|
|
+ return -EINVAL;
|
|
+ gpio = param[0];
|
|
+ freq = param[1];
|
|
+ duty = param[2];
|
|
+ if (gpio == (SUNXI_PA_BASE + 5)) {
|
|
+ pwm_id = 0;
|
|
+ } else if (gpio == (SUNXI_PA_BASE + 6)) {
|
|
+ pwm_id = 1;
|
|
+ } else {
|
|
+ printk("Invalid pwm gpio %d\n", gpio);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (duty < 0 || duty > 1000) {
|
|
+ printk("Invalid pwm duty %d\n", duty);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (is_pwm_working[pwm_id] == 1) {
|
|
+ matrix_pwm_hw_exit(pwm_id, gpio);
|
|
+ }
|
|
+
|
|
+ if ((ret = matrix_pwm_hw_init(pwm_id, gpio))) {
|
|
+ return ret;
|
|
+ }
|
|
+ is_pwm_working[pwm_id] = 1;
|
|
+ if ((ret = pwm_set_freq(pwm_id, gpio, freq, duty))) {
|
|
+ return ret;
|
|
+ }
|
|
+ break;
|
|
+ case PWM_IOCTL_STOP:
|
|
+ if (copy_from_user(&gpio, (void __user *)arg, sizeof(gpio)))
|
|
+ return -EINVAL;
|
|
+ if (gpio == (SUNXI_PA_BASE + 5)) {
|
|
+ pwm_id = 0;
|
|
+ } else if (gpio == (SUNXI_PA_BASE + 6)) {
|
|
+ pwm_id = 1;
|
|
+ } else {
|
|
+ printk("Invalid pwm gpio %d\n", gpio);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ if (is_pwm_working[pwm_id] == 1) {
|
|
+ matrix_pwm_hw_exit(pwm_id, gpio);
|
|
+ is_pwm_working[pwm_id] = 0;
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ printk("%s unsupported pwm ioctl %d", __FUNCTION__, cmd);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct file_operations matrix_pwm_ops = {
|
|
+ .owner = THIS_MODULE,
|
|
+ .open = matrix_pwm_open,
|
|
+ .release = matrix_pwm_close,
|
|
+ .unlocked_ioctl = matrix_pwm_ioctl,
|
|
+};
|
|
+
|
|
+static struct miscdevice matrix_misc_dev = {
|
|
+ .minor = MISC_DYNAMIC_MINOR,
|
|
+ .name = DEVICE_NAME,
|
|
+ .fops = &matrix_pwm_ops,
|
|
+};
|
|
+
|
|
+static int __init matrix_pwm_init(void)
|
|
+{
|
|
+ int ret;
|
|
+ ret = misc_register(&matrix_misc_dev);
|
|
+ printk("Matirx PWM init\n");
|
|
+
|
|
+ sema_init(&lock, 1);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void __exit matrix_pwm_exit(void) {
|
|
+ misc_deregister(&matrix_misc_dev);
|
|
+ printk("Matirx PWM exit\n");
|
|
+}
|
|
+
|
|
+module_init(matrix_pwm_init);
|
|
+module_exit(matrix_pwm_exit);
|
|
+
|
|
+MODULE_LICENSE("GPL");
|
|
+MODULE_AUTHOR("FriendlyARM Inc.");
|
|
+MODULE_DESCRIPTION("FriendlyARM Matrix PWM Driver");
|
|
+
|
|
diff --git a/drivers/char/matrix_rotary_encoder.c b/drivers/char/matrix_rotary_encoder.c
|
|
new file mode 100644
|
|
index 0000000..97fcb76
|
|
--- /dev/null
|
|
+++ b/drivers/char/matrix_rotary_encoder.c
|
|
@@ -0,0 +1,205 @@
|
|
+#include <linux/module.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/moduleparam.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/hrtimer.h>
|
|
+#include <linux/ktime.h>
|
|
+#include <linux/device.h>
|
|
+#include <linux/kdev_t.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/sched.h>
|
|
+#include <linux/of_device.h>
|
|
+
|
|
+#include <asm/mach/irq.h>
|
|
+#include <mach/platform.h>
|
|
+
|
|
+static int has_init = 0;
|
|
+static int sw_pin = -1; // func: int
|
|
+static int sia_pin = -1; // func: int
|
|
+static int sib_pin = -1; // func: input
|
|
+static int sia_irq = -1;
|
|
+static int sw_irq = -1;
|
|
+static int counter = 0;
|
|
+static int sw = 0;
|
|
+
|
|
+static void rotary_sensor_hw_exit(void);
|
|
+static int rotary_sensor_hw_init(void );
|
|
+
|
|
+
|
|
+static ssize_t rotary_sensor_sw_read(struct device *dev, struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ if ( sw_pin != -1 && sia_pin != -1 && sib_pin != -1) {
|
|
+ return sprintf(buf, "%d\n", sw);
|
|
+ }
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static ssize_t rotary_sensor_value_read(struct device *dev, struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ if ( sw_pin != -1 && sia_pin != -1 && sib_pin != -1) {
|
|
+ return sprintf(buf, "%d\n", counter);
|
|
+ }
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static ssize_t rotary_sensor_gpio_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ return sprintf(buf, "%d,%d,%d\n", sw_pin, sia_pin, sib_pin);
|
|
+}
|
|
+
|
|
+static ssize_t rotary_sensor_gpio_store(struct device *device, struct device_attribute *attr, const char *buf, size_t count)
|
|
+{
|
|
+ if ( has_init ==0 ) {
|
|
+ sscanf(buf,"%d,%d,%d ", &sw_pin, &sia_pin, &sib_pin);
|
|
+ printk(KERN_ERR"buf=%s\n", buf);
|
|
+ if (rotary_sensor_hw_init()) {
|
|
+ has_init = 0;
|
|
+ return -1;
|
|
+ }
|
|
+ else {
|
|
+ has_init = 1;
|
|
+ }
|
|
+ } else {
|
|
+ rotary_sensor_hw_exit();
|
|
+ has_init = 0;
|
|
+ }
|
|
+
|
|
+ return count;
|
|
+}
|
|
+static struct device_attribute value_attr = __ATTR(value, S_IRUGO, rotary_sensor_value_read, NULL);
|
|
+static struct device_attribute sw_attr = __ATTR(sw,S_IRUGO, rotary_sensor_sw_read, NULL);
|
|
+static struct device_attribute gpio_attr = __ATTR(gpio, S_IRUGO|S_IWUGO, rotary_sensor_gpio_show, rotary_sensor_gpio_store);
|
|
+
|
|
+/* sys attribte group */
|
|
+static struct attribute *attrs[] = {
|
|
+ &value_attr.attr, &sw_attr.attr, &gpio_attr.attr, NULL,
|
|
+};
|
|
+
|
|
+static struct attribute_group attr_group = {
|
|
+ .attrs = (struct attribute **)attrs,
|
|
+};
|
|
+
|
|
+
|
|
+static irqreturn_t sw_isr(int irq, void *data)
|
|
+{
|
|
+ if (gpio_get_value(sw_pin) == 1) {
|
|
+ sw = 0;
|
|
+ } else {
|
|
+ sw = 1;
|
|
+ }
|
|
+ // printk("%s sw=%d\n", __func__, sw);
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+static irqreturn_t rotate_isr(int irq, void *data)
|
|
+{
|
|
+ if (gpio_get_value(sib_pin) == 1) {
|
|
+ counter++;
|
|
+ } else {
|
|
+ counter--;
|
|
+ }
|
|
+ // printk("%s value=%d\n", __func__, counter);
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+static void rotary_sensor_hw_exit(void)
|
|
+{
|
|
+ if (sia_irq != -1)
|
|
+ free_irq(sia_irq, NULL);
|
|
+ if (sw_irq != -1)
|
|
+ free_irq(sw_irq, NULL);
|
|
+ if (sib_pin != -1)
|
|
+ gpio_free(sib_pin);
|
|
+ if (sia_pin != -1)
|
|
+ gpio_free(sia_pin);
|
|
+ if (sw_pin != -1)
|
|
+ gpio_free(sw_pin);
|
|
+ sw_pin = sia_pin = sib_pin = -1;
|
|
+}
|
|
+
|
|
+static int rotary_sensor_hw_init(void )
|
|
+{
|
|
+ int ret = -1;
|
|
+
|
|
+ ret = gpio_request(sw_pin, "sw");
|
|
+ if (ret) {
|
|
+ printk(KERN_ERR"gpio request sw_pin fail:%d\n", sw_pin);
|
|
+ return -1;
|
|
+ }
|
|
+ ret = gpio_request(sia_pin, "sia_pin");
|
|
+ if (ret) {
|
|
+ printk(KERN_ERR"gpio request sia_pin fail:%d\n", sia_pin);
|
|
+ goto fail_gpio_sw;
|
|
+ }
|
|
+ ret = gpio_request(sib_pin, "sib_pin");
|
|
+ if (ret) {
|
|
+ printk(KERN_ERR"gpio request sib_pin fail:%d\n", sia_pin);
|
|
+ goto fail_gpio_sia;
|
|
+ }
|
|
+
|
|
+ sw_irq = gpio_to_irq(sw_pin);
|
|
+ ret = request_irq(sw_irq, sw_isr, IRQ_TYPE_EDGE_BOTH, "rotary_sensor_sw", NULL);
|
|
+ if (ret) {
|
|
+ printk(KERN_ERR"%s fail to request_irq, gpio=%d irq=%d\n", __func__, sw_pin, sw_irq);
|
|
+ goto fail_gpio_sib;
|
|
+ }
|
|
+
|
|
+ sia_irq = gpio_to_irq(sia_pin);
|
|
+ ret = request_irq(sia_irq, rotate_isr, IRQ_TYPE_EDGE_FALLING , "rotary_sensor_sia", NULL);
|
|
+ if (ret) {
|
|
+ printk(KERN_ERR"%s fail to request_irq, gpio=%d irq=%d\n", __func__, sia_pin, sia_irq);
|
|
+ goto fail_irq_sw;
|
|
+ }
|
|
+
|
|
+ gpio_direction_input(sib_pin);
|
|
+
|
|
+ return ret;
|
|
+
|
|
+fail_irq_sw:
|
|
+ free_irq(sw_irq, NULL);
|
|
+fail_gpio_sib:
|
|
+ gpio_free(sib_pin);
|
|
+fail_gpio_sia:
|
|
+ gpio_free(sia_pin);
|
|
+fail_gpio_sw:
|
|
+ gpio_free(sw_pin);
|
|
+ return ret;
|
|
+
|
|
+}
|
|
+static struct kobject *kobj = NULL;
|
|
+static int rotary_sensor_init(void)
|
|
+{
|
|
+ int ret = 0;
|
|
+ printk(KERN_INFO "Matrix-rotary_encoder init.\n");
|
|
+
|
|
+ kobj = kobject_create_and_add("rotary_encoder", &platform_bus.kobj);
|
|
+ if (!kobj) {
|
|
+ pr_err("%s: failed to kobject_create_and_add for rotary_encoder\n", __func__);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ ret = sysfs_create_group(kobj, &attr_group);
|
|
+ if (ret) {
|
|
+ pr_err("%s: failed to sysfs_create_group for rotary_encoder\n", __func__);
|
|
+ kobject_del(kobj);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void rotary_sensor_exit(void)
|
|
+{
|
|
+ printk(KERN_INFO "Matrix-rotary_encoder exit.\n");
|
|
+ sysfs_remove_group(kobj, &attr_group);
|
|
+ kobject_put(kobj);
|
|
+ kobj = NULL;
|
|
+}
|
|
+
|
|
+module_init(rotary_sensor_init);
|
|
+module_exit(rotary_sensor_exit);
|
|
+
|
|
+MODULE_LICENSE("GPL v2");
|
|
+MODULE_AUTHOR("FriendlyARM");
|
|
+MODULE_DESCRIPTION("Driver for Matrix-Rotary_Sensor");
|
|
diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c
|
|
index 1cf72fe..81fbe55 100644
|
|
--- a/drivers/input/misc/adxl34x.c
|
|
+++ b/drivers/input/misc/adxl34x.c
|
|
@@ -223,7 +223,7 @@ static const struct adxl34x_platform_data adxl34x_default_init = {
|
|
.free_fall_threshold = 8,
|
|
.free_fall_time = 0x20,
|
|
.data_rate = 8,
|
|
- .data_range = ADXL_FULL_RES,
|
|
+ .data_range = ADXL_FULL_RES | INT_INVERT,
|
|
|
|
.ev_type = EV_ABS,
|
|
.ev_code_x = ABS_X, /* EV_REL */
|
|
@@ -236,6 +236,9 @@ static const struct adxl34x_platform_data adxl34x_default_init = {
|
|
.watermark = 0,
|
|
};
|
|
|
|
+static irqreturn_t adxl34x_irq(int irq, void *handle);
|
|
+static int adxl34x_read_without_int(int irq, void* handle);
|
|
+
|
|
static void adxl34x_get_triple(struct adxl34x *ac, struct axis_triple *axis)
|
|
{
|
|
short buf[3];
|
|
@@ -296,6 +299,14 @@ static void adxl34x_do_tap(struct adxl34x *ac,
|
|
adxl34x_send_key_events(ac, pdata, status, false);
|
|
}
|
|
|
|
+static int adxl34x_read_without_int(int irq, void* handle)
|
|
+{
|
|
+ if (adxl34x_irq(irq, handle) != IRQ_HANDLED) {
|
|
+ return -1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static irqreturn_t adxl34x_irq(int irq, void *handle)
|
|
{
|
|
struct adxl34x *ac = handle;
|
|
@@ -486,6 +497,10 @@ static ssize_t adxl34x_calibrate_show(struct device *dev,
|
|
struct adxl34x *ac = dev_get_drvdata(dev);
|
|
ssize_t count;
|
|
|
|
+ if (adxl34x_read_without_int(0, ac)) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
mutex_lock(&ac->mutex);
|
|
count = sprintf(buf, "%d,%d,%d\n",
|
|
ac->hwcal.x * 4 + ac->swcal.x,
|
|
@@ -607,6 +622,9 @@ static ssize_t adxl34x_position_show(struct device *dev,
|
|
struct adxl34x *ac = dev_get_drvdata(dev);
|
|
ssize_t count;
|
|
|
|
+ if (adxl34x_read_without_int(0, ac)) {
|
|
+ return 0;
|
|
+ }
|
|
mutex_lock(&ac->mutex);
|
|
count = sprintf(buf, "(%d, %d, %d)\n",
|
|
ac->saved.x, ac->saved.y, ac->saved.z);
|
|
@@ -810,14 +828,16 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
|
|
ac->fifo_delay = false;
|
|
|
|
ac->bops->write(dev, POWER_CTL, 0);
|
|
-
|
|
+ // not use int
|
|
+#if 0
|
|
err = request_threaded_irq(ac->irq, NULL, adxl34x_irq,
|
|
- IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
|
|
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
|
dev_name(dev), ac);
|
|
if (err) {
|
|
dev_err(dev, "irq %d busy?\n", ac->irq);
|
|
goto err_free_mem;
|
|
}
|
|
+#endif
|
|
|
|
err = sysfs_create_group(&dev->kobj, &adxl34x_attr_group);
|
|
if (err)
|
|
@@ -884,6 +904,13 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
|
|
|
|
ac->pdata.power_mode &= (PCTL_AUTO_SLEEP | PCTL_LINK);
|
|
|
|
+ __adxl34x_enable(ac);
|
|
+#if 0
|
|
+ int start = 0x1D;
|
|
+ for(; start < 0x3C; start++) {
|
|
+ printk("reg[%x]=%x\n", start, AC_READ(ac, start));
|
|
+ }
|
|
+#endif
|
|
return ac;
|
|
|
|
err_remove_attr:
|
|
diff --git a/drivers/staging/iio/humidity/Makefile b/drivers/staging/iio/humidity/Makefile
|
|
new file mode 100644
|
|
index 0000000..d5d36c0
|
|
--- /dev/null
|
|
+++ b/drivers/staging/iio/humidity/Makefile
|
|
@@ -0,0 +1,5 @@
|
|
+#
|
|
+# Makefile for IIO humidity sensor drivers
|
|
+#
|
|
+
|
|
+obj-$(CONFIG_DHT11) += dht11.o
|
|
diff --git a/drivers/staging/iio/humidity/dht11.c b/drivers/staging/iio/humidity/dht11.c
|
|
new file mode 100644
|
|
index 0000000..a751a54
|
|
--- /dev/null
|
|
+++ b/drivers/staging/iio/humidity/dht11.c
|
|
@@ -0,0 +1,366 @@
|
|
+/*
|
|
+ * DHT11/DHT22 bit banging GPIO driver
|
|
+ *
|
|
+ * Copyright (c) Harald Geyer <harald@ccbib.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ */
|
|
+
|
|
+#include <linux/err.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/device.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/printk.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/sysfs.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/wait.h>
|
|
+#include <linux/bitops.h>
|
|
+#include <linux/completion.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/of_gpio.h>
|
|
+#include <linux/pinctrl/pinconf.h>
|
|
+#include <linux/pinctrl/pinconf-sunxi.h>
|
|
+#include <linux/pinctrl/consumer.h>
|
|
+#include <linux/kthread.h>
|
|
+
|
|
+#include <mach/platform.h>
|
|
+
|
|
+#include "../iio.h"
|
|
+
|
|
+//#define DHT11_DEBUG 1
|
|
+#define DRIVER_NAME "dht11"
|
|
+
|
|
+#define DHT11_DATA_VALID_TIME 2000000000 /* 2s in ns */
|
|
+
|
|
+#define DHT11_EDGES_PREAMBLE 4
|
|
+#define DHT11_BITS_PER_READ 40
|
|
+#define DHT11_EDGES_PER_READ (2*DHT11_BITS_PER_READ + DHT11_EDGES_PREAMBLE)
|
|
+
|
|
+/* Data transmission timing (nano seconds) */
|
|
+#define DHT11_START_TRANSMISSION 18 /* ms */
|
|
+#define DHT11_SENSOR_RESPONSE 80000
|
|
+#define DHT11_START_BIT 50000
|
|
+#define DHT11_DATA_BIT_LOW 27000
|
|
+#define DHT11_DATA_BIT_HIGH 70000
|
|
+
|
|
+#define DATA_START_FLAG_MIN (50000)
|
|
+#define DATA_START_FLAG_MAX (60000)
|
|
+#define DATA_ONE_MIN (65000)
|
|
+#define DATA_ONE_MAX (75000)
|
|
+#define DATA_ZERO_MIN (20000)
|
|
+#define DATA_ZERO_MAX (30000)
|
|
+
|
|
+
|
|
+struct dht11 {
|
|
+ struct device *dev;
|
|
+
|
|
+ int gpio;
|
|
+ int irq;
|
|
+
|
|
+ struct completion completion;
|
|
+
|
|
+ s64 timestamp;
|
|
+ int temperature;
|
|
+ int humidity;
|
|
+
|
|
+ /* num_edges: -1 means "no transmission in progress" */
|
|
+ int num_edges;
|
|
+ struct {s64 ts; int value; } edges[DHT11_EDGES_PER_READ];
|
|
+};
|
|
+
|
|
+static int gpio = -1;
|
|
+static int dht11_read_flag = 0;
|
|
+static unsigned char dht11_decode_byte(int *timing)
|
|
+{
|
|
+ unsigned char ret = 0;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < 8; ++i) {
|
|
+ ret <<= 1;
|
|
+ ret +=timing[i];
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int dht11_decode(struct dht11 *dht11, int *timing)
|
|
+{
|
|
+ unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum;
|
|
+
|
|
+#ifdef DHT11_DEBUG
|
|
+ int i = 0;
|
|
+ for(i=0; i<DHT11_BITS_PER_READ; i++)
|
|
+ printk(KERN_ERR"%02d %d\n", i, timing[i]);
|
|
+#endif
|
|
+ hum_int = dht11_decode_byte(timing);
|
|
+ hum_dec = dht11_decode_byte(&timing[8]);
|
|
+ temp_int = dht11_decode_byte(&timing[16]);
|
|
+ temp_dec = dht11_decode_byte(&timing[24]);
|
|
+ checksum = dht11_decode_byte(&timing[32]);
|
|
+
|
|
+#ifdef DHT11_DEBUG
|
|
+ printk(KERN_ERR"%d + %d + %d + %d = %d\n", hum_int, hum_dec, temp_int, temp_dec, checksum);
|
|
+#endif
|
|
+ if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum) {
|
|
+ dev_err(dht11->dev,
|
|
+ "checksum error %d %d %d %d %d\n",
|
|
+ hum_int, hum_dec, temp_int, temp_dec, checksum);
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ dht11->timestamp = iio_get_time_ns();
|
|
+ if (hum_int < 20) { /* DHT22 */
|
|
+ dht11->temperature = (((temp_int & 0x7f) << 8) + temp_dec) *
|
|
+ ((temp_int & 0x80) ? -100 : 100);
|
|
+ dht11->humidity = ((hum_int << 8) + hum_dec) * 100;
|
|
+ } else if (temp_dec == 0 && hum_dec == 0) { /* DHT11 */
|
|
+ dht11->temperature = temp_int * 1000;
|
|
+ dht11->humidity = hum_int * 1000;
|
|
+ } else {
|
|
+ dev_err(dht11->dev,
|
|
+ "Don't know how to decode data: %d %d %d %d\n",
|
|
+ hum_int, hum_dec, temp_int, temp_dec);
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int dht11_read_thread(void *__dev)
|
|
+{
|
|
+ struct dht11 *dht11 = (struct dht11 *)__dev;
|
|
+ int value = 0;
|
|
+
|
|
+#ifdef DHT11_DEBUG
|
|
+ printk(KERN_INFO"%s start\n", __func__);
|
|
+#endif
|
|
+ if (gpio_direction_output(dht11->gpio, 0))
|
|
+ return -1;
|
|
+ msleep(DHT11_START_TRANSMISSION);
|
|
+ gpio_direction_input(dht11->gpio);
|
|
+ dht11->edges[dht11->num_edges].value = gpio_get_value(dht11->gpio);
|
|
+ dht11->edges[dht11->num_edges].ts = iio_get_time_ns();
|
|
+ while (dht11->num_edges < DHT11_EDGES_PER_READ && dht11_read_flag == 1) {
|
|
+ value = gpio_get_value(dht11->gpio);
|
|
+ if (dht11->edges[dht11->num_edges].value != value) {
|
|
+ dht11->num_edges++;
|
|
+ dht11->edges[dht11->num_edges].ts = iio_get_time_ns();
|
|
+ dht11->edges[dht11->num_edges].value = value;
|
|
+ if (dht11->num_edges == DHT11_EDGES_PER_READ)
|
|
+ complete(&dht11->completion);
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int dht11_read_raw(struct iio_dev *iio_dev,
|
|
+ const struct iio_chan_spec *chan,
|
|
+ int *val, int *val2, long m)
|
|
+{
|
|
+ struct dht11 *dht11 = iio_priv(iio_dev);
|
|
+ int ret;
|
|
+ int i, j;
|
|
+ int timing[DHT11_BITS_PER_READ], time;
|
|
+ struct task_struct *th;
|
|
+
|
|
+ if (dht11->timestamp + DHT11_DATA_VALID_TIME < iio_get_time_ns()) {
|
|
+ dht11->num_edges = 0;
|
|
+ dht11->completion.done = 0;
|
|
+ th = kthread_create(dht11_read_thread, dht11, "dht11-read");
|
|
+ if (IS_ERR(th)) {
|
|
+ ret = -1;
|
|
+ goto err;
|
|
+ }
|
|
+ dht11_read_flag = 1;
|
|
+ wake_up_process(th);
|
|
+ ret = wait_for_completion_killable_timeout(&dht11->completion, HZ);
|
|
+ dht11_read_flag = 0;
|
|
+ if(th)
|
|
+ kthread_stop(th);
|
|
+ if (ret == 0) {
|
|
+ dev_err(&iio_dev->dev, "dht11 read raw timeout\n");
|
|
+ ret = -1;
|
|
+ //goto err;
|
|
+ }
|
|
+ for(i=0,j=0; i<dht11->num_edges; i++) {
|
|
+ if (i != 0) {
|
|
+#ifdef DHT11_DEBUG
|
|
+ printk(KERN_DEBUG"%02d ts=%lld value=%d pass=%lld\n", i, dht11->edges[i].ts, dht11->edges[i].value, dht11->edges[i].ts - dht11->edges[i-1].ts);
|
|
+#endif
|
|
+ time = dht11->edges[i].ts - dht11->edges[i-1].ts;
|
|
+ }
|
|
+ if (i > 3) {
|
|
+ if ((i%2) == 0) { // one bit start always about 50us
|
|
+ if (time<DATA_START_FLAG_MIN || time>DATA_START_FLAG_MAX) {
|
|
+ printk(KERN_ERR"bit start without 50us, time=%d\n", time);
|
|
+ ret = -EINVAL;
|
|
+ goto err;
|
|
+ }
|
|
+ } else {
|
|
+ time = dht11->edges[i].ts - dht11->edges[i-1].ts;
|
|
+ if (time > DATA_ZERO_MIN && time < DATA_ZERO_MAX)
|
|
+ timing[j] = 0;
|
|
+ else if (time > DATA_ONE_MIN && time < DATA_ONE_MAX)
|
|
+ timing[j]= 1;
|
|
+ else {
|
|
+ printk(KERN_ERR"bit value is not 1 or 0, time=%d\n", time);
|
|
+ ret = -EINVAL;
|
|
+ goto err;
|
|
+ }
|
|
+ j++;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ret = dht11_decode(dht11, timing);
|
|
+ if (ret)
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ ret = IIO_VAL_INT;
|
|
+ if (chan->type == IIO_TEMP)
|
|
+ *val = dht11->temperature;
|
|
+ else if (chan->type == IIO_HUMIDITYRELATIVE)
|
|
+ *val = dht11->humidity;
|
|
+ else
|
|
+ ret = -EINVAL;
|
|
+err:
|
|
+ dht11->num_edges = -1;
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const struct iio_info dht11_iio_info = {
|
|
+ .driver_module = THIS_MODULE,
|
|
+ .read_raw = dht11_read_raw,
|
|
+};
|
|
+
|
|
+static const struct iio_chan_spec dht11_chan_spec[] = {
|
|
+ {
|
|
+ .type = IIO_TEMP,
|
|
+ .processed_val = IIO_PROCESSED,
|
|
+ },
|
|
+ {
|
|
+ .type = IIO_HUMIDITYRELATIVE,
|
|
+ .processed_val = IIO_PROCESSED,
|
|
+ }
|
|
+};
|
|
+
|
|
+static const struct of_device_id dht11_dt_ids[] = {
|
|
+ { .compatible = "dht11", },
|
|
+ { }
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, dht11_dt_ids);
|
|
+
|
|
+static int dht11_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct device *dev = &pdev->dev;
|
|
+ struct dht11 *dht11;
|
|
+ struct iio_dev *iio;
|
|
+ int ret = -1;
|
|
+
|
|
+ iio = iio_allocate_device(sizeof(*dht11));
|
|
+ if (!iio) {
|
|
+ dev_err(dev, "Failed to allocate IIO device\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ dht11 = iio_priv(iio);
|
|
+ dht11->dev = dev;
|
|
+ dht11->gpio = gpio;
|
|
+
|
|
+ ret = gpio_request(dht11->gpio, pdev->name);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ dht11->timestamp = iio_get_time_ns() - DHT11_DATA_VALID_TIME - 1;
|
|
+ dht11->num_edges = -1;
|
|
+
|
|
+ platform_set_drvdata(pdev, iio);
|
|
+
|
|
+ init_completion(&dht11->completion);
|
|
+ iio->name = pdev->name;
|
|
+ iio->dev.parent = &pdev->dev;
|
|
+ iio->info = &dht11_iio_info;
|
|
+ iio->modes = INDIO_DIRECT_MODE;
|
|
+ iio->channels = dht11_chan_spec;
|
|
+ iio->num_channels = ARRAY_SIZE(dht11_chan_spec);
|
|
+
|
|
+ return iio_device_register(iio);
|
|
+}
|
|
+
|
|
+static int dht11_remove(struct platform_device *pdev)
|
|
+{
|
|
+ struct iio_dev *iio = platform_get_drvdata(pdev);
|
|
+ struct dht11 *dht11 = iio_priv(iio);
|
|
+
|
|
+ iio_device_unregister(iio);
|
|
+ gpio_free(dht11->gpio);
|
|
+ iio_free_device(iio);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct platform_driver dht11_driver = {
|
|
+ .driver = {
|
|
+ .name = DRIVER_NAME,
|
|
+ .owner = THIS_MODULE,
|
|
+ .of_match_table = dht11_dt_ids,
|
|
+ },
|
|
+ .probe = dht11_probe,
|
|
+ .remove = dht11_remove,
|
|
+};
|
|
+
|
|
+void matrix_dht11_device_release(struct device *dev)
|
|
+{
|
|
+}
|
|
+
|
|
+static struct platform_device dht11_device = {
|
|
+ .name = "dht11",
|
|
+ .id = -1,
|
|
+ .num_resources = 0,
|
|
+ .dev = {
|
|
+ .release = matrix_dht11_device_release,
|
|
+ }
|
|
+};
|
|
+
|
|
+static int __init dht11_init(void)
|
|
+{
|
|
+ int ret = -1;
|
|
+
|
|
+ printk("plat: add device matrix-dht11, gpio=%d\n", gpio);
|
|
+ if ((ret = platform_device_register(&dht11_device))) {
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ if ((ret = platform_driver_register(&dht11_driver))) {
|
|
+ platform_device_unregister(&dht11_device);
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void __exit dht11_exit(void)
|
|
+{
|
|
+ platform_driver_unregister(&dht11_driver);
|
|
+ platform_device_unregister(&dht11_device);
|
|
+ gpio = -1;
|
|
+}
|
|
+
|
|
+module_init(dht11_init);
|
|
+module_exit(dht11_exit);
|
|
+MODULE_AUTHOR("Harald Geyer <harald@ccbib.org>");
|
|
+MODULE_DESCRIPTION("DHT11 humidity/temperature sensor driver");
|
|
+MODULE_LICENSE("GPL v2");
|
|
+module_param(gpio, int, 0644);
|
|
diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c
|
|
index e16500a..7e4421e 100755
|
|
--- a/drivers/staging/iio/industrialio-core.c
|
|
+++ b/drivers/staging/iio/industrialio-core.c
|
|
@@ -68,6 +68,7 @@ static const char * const iio_chan_type_name_spec[] = {
|
|
[IIO_ANGL] = "angl",
|
|
[IIO_TIMESTAMP] = "timestamp",
|
|
[IIO_CAPACITANCE] = "capacitance",
|
|
+ [IIO_HUMIDITYRELATIVE] = "humidityrelative",
|
|
[IIO_QUATERNION] = "quaternion",
|
|
};
|
|
|
|
diff --git a/drivers/staging/iio/types.h b/drivers/staging/iio/types.h
|
|
index 291c783..616c141 100755
|
|
--- a/drivers/staging/iio/types.h
|
|
+++ b/drivers/staging/iio/types.h
|
|
@@ -27,6 +27,7 @@ enum iio_chan_type {
|
|
IIO_ANGL,
|
|
IIO_TIMESTAMP,
|
|
IIO_CAPACITANCE,
|
|
+ IIO_HUMIDITYRELATIVE,
|
|
IIO_QUATERNION,
|
|
};
|
|
|
|
diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile
|
|
index c5a3e96..88ee685 100644
|
|
--- a/drivers/w1/masters/Makefile
|
|
+++ b/drivers/w1/masters/Makefile
|
|
@@ -8,5 +8,5 @@ obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o
|
|
obj-$(CONFIG_W1_MASTER_MXC) += mxc_w1.o
|
|
|
|
obj-$(CONFIG_W1_MASTER_DS1WM) += ds1wm.o
|
|
-obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o
|
|
+obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o w1-gpio-board.o
|
|
obj-$(CONFIG_HDQ_MASTER_OMAP) += omap_hdq.o
|
|
diff --git a/drivers/w1/masters/w1-gpio-board.c b/drivers/w1/masters/w1-gpio-board.c
|
|
new file mode 100644
|
|
index 0000000..11aa1e4
|
|
--- /dev/null
|
|
+++ b/drivers/w1/masters/w1-gpio-board.c
|
|
@@ -0,0 +1,59 @@
|
|
+/*
|
|
+ * w1-gpio-board.c - Board driver for GPIO w1 bus master
|
|
+ *
|
|
+ * Copyright (C) 2016 FriendlyARM (www.friendlyarm.com)
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License version 2
|
|
+ * as published by the Free Software Foundation.
|
|
+ */
|
|
+#include <linux/init.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/w1-gpio.h>
|
|
+#include <linux/gpio.h>
|
|
+
|
|
+#include <mach/platform.h>
|
|
+
|
|
+static int gpio = -1;
|
|
+module_param(gpio, int, 0644);
|
|
+
|
|
+
|
|
+static struct w1_gpio_platform_data w1_gpio_pdata = {
|
|
+ .pin = -1,
|
|
+ .is_open_drain = 0,
|
|
+};
|
|
+
|
|
+static void w1_device_release(struct device *dev) {
|
|
+ // nothing here yet
|
|
+}
|
|
+
|
|
+static struct platform_device matrix_w1_device = {
|
|
+ .name = "w1-gpio",
|
|
+ .id = -1,
|
|
+ .dev = {
|
|
+ .release = w1_device_release,
|
|
+ .platform_data = &w1_gpio_pdata,
|
|
+ }
|
|
+};
|
|
+
|
|
+
|
|
+static int __init w1_gpio_board_init(void)
|
|
+{
|
|
+ w1_gpio_pdata.pin = gpio;
|
|
+ printk("plat: add device w1-gpio, gpio=%d\n", w1_gpio_pdata.pin);
|
|
+ return platform_device_register(&matrix_w1_device);
|
|
+}
|
|
+
|
|
+static void __exit w1_gpio_board_exit(void)
|
|
+{
|
|
+ platform_device_unregister(&matrix_w1_device);
|
|
+}
|
|
+
|
|
+module_init(w1_gpio_board_init);
|
|
+module_exit(w1_gpio_board_exit);
|
|
+
|
|
+MODULE_DESCRIPTION("Board driver for GPIO w1 bus master");
|
|
+MODULE_AUTHOR("FriendlyARM");
|
|
+MODULE_LICENSE("GPL");
|
|
diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c
|
|
index df600d1..28f8d7d 100644
|
|
--- a/drivers/w1/masters/w1-gpio.c
|
|
+++ b/drivers/w1/masters/w1-gpio.c
|
|
@@ -42,7 +42,7 @@ static u8 w1_gpio_read_bit(void *data)
|
|
return gpio_get_value(pdata->pin) ? 1 : 0;
|
|
}
|
|
|
|
-static int __init w1_gpio_probe(struct platform_device *pdev)
|
|
+static int w1_gpio_probe(struct platform_device *pdev)
|
|
{
|
|
struct w1_bus_master *master;
|
|
struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
|
|
@@ -56,8 +56,10 @@ static int __init w1_gpio_probe(struct platform_device *pdev)
|
|
return -ENOMEM;
|
|
|
|
err = gpio_request(pdata->pin, "w1");
|
|
- if (err)
|
|
+ if (err) {
|
|
+ dev_err(&pdev->dev, "failed to request GPIO %d\n", pdata->pin);
|
|
goto free_master;
|
|
+ }
|
|
|
|
master->data = pdata;
|
|
master->read_bit = w1_gpio_read_bit;
|
|
@@ -89,7 +91,7 @@ static int __init w1_gpio_probe(struct platform_device *pdev)
|
|
return err;
|
|
}
|
|
|
|
-static int __exit w1_gpio_remove(struct platform_device *pdev)
|
|
+static int w1_gpio_remove(struct platform_device *pdev)
|
|
{
|
|
struct w1_bus_master *master = platform_get_drvdata(pdev);
|
|
struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
|
|
@@ -136,14 +138,15 @@ static struct platform_driver w1_gpio_driver = {
|
|
.name = "w1-gpio",
|
|
.owner = THIS_MODULE,
|
|
},
|
|
- .remove = __exit_p(w1_gpio_remove),
|
|
+ .probe = w1_gpio_probe,
|
|
+ .remove = w1_gpio_remove,
|
|
.suspend = w1_gpio_suspend,
|
|
.resume = w1_gpio_resume,
|
|
};
|
|
|
|
static int __init w1_gpio_init(void)
|
|
{
|
|
- return platform_driver_probe(&w1_gpio_driver, w1_gpio_probe);
|
|
+ return platform_driver_register(&w1_gpio_driver);
|
|
}
|
|
|
|
static void __exit w1_gpio_exit(void)
|