Compare commits

...

16 Commits

Author SHA1 Message Date
Marek Kwaczynski
fe3a64d475 iwinfo.uc: Fix access to undefined htmode object
iwinfo command failed due to undefined htmode object

Fixes: WIFI-14666

Signed-off-by: Marek Kwaczynski <marek@shasta.cloud>
(cherry picked from commit 7ee4a766e73676ce14c6013e032c55566b42196c)
2025-06-06 17:15:08 +02:00
Ken
6add44ae27 qca-wifi-7: fix invalid port mapping due to syntax error in 02_network
issue was introduced by edfd2883f5

Fixes: WIFI-14650
Signed-off-by: Ken <xshi@actiontec.com>
2025-05-30 07:24:33 +02:00
John Crispin
14a0c2d272 qca-wifi-7: add missing Kbuild symbols
Signed-off-by: John Crispin <john@phrozen.org>
2025-05-27 13:48:08 +02:00
John Crispin
9e769c85cb .github/workflows/: add more boards
Signed-off-by: John Crispin <john@phrozen.org>
2025-05-27 10:39:57 +02:00
mike_ding
d6e1008c7a Support dual image and fix reset button does not work issue
Signed-off-by: mike_ding <mike_ding@sdc.sercomm.com>
2025-05-27 10:39:57 +02:00
John Crispin
0a4c10d6cc ucentral-schema: update to latest HEAD
b4cfdc6 cmd_upgrade: implement secure download

Signed-off-by: John Crispin <john@phrozen.org>
2025-05-26 16:23:17 +02:00
jackcybertan
edfd2883f5 qca-wifi-7: Support for CyberTAN RAP750E-S AP
Signed-off-by: jackcybertan <jack.tsai@cybertan.com.tw>
2025-05-26 16:23:17 +02:00
Tanya Singh
f6ac6f791e mediatek: Fix typo in the name of the /etc/init.d/bootcount script
Fixes: WIFI-14579
Signed-off-by: Tanya Singh <tanya_singh@accton.com>
2025-05-26 16:23:17 +02:00
Tanya Singh
88fe15a985 mediatek: include patched hostapd for EAP112
Fixes: WIFI-14645
Signed-off-by: Tanya Singh <tanya_singh@accton.com>
2025-05-26 16:23:17 +02:00
Justin.Guo
a9f47c9e1e qca-wifi-7: CIG WiFi7 WF-672A bring up
* bring up wf672a
* add drivers lsm303agr rtl8221d ilps22qs
* add cig-wifi-mode-sw for switching radio to 2 bands or 3 bands

Fixes: WIFI-14509
Signed-off-by: Justin.Guo <guoxijun@actiontec.com>
2025-05-26 16:23:17 +02:00
Marek Kwaczynski
f17314a2d3 qca-wifi-7: hostapd: fix missing PSK assignment for EMPSK
When using psk2-radius in combination with enhanced MPSK,
the passphrase was not properly propagated to user scripts
via the ucode interface, because the PSK field was not set
in the connected station context.

This patch fixes that by copying the passphrase into the
psk field.

Signed-off-by: Marek Kwaczynski <marek@shasta.cloud>
2025-05-26 16:23:17 +02:00
Marek Kwaczynski
29739ebd13 qca-wifi-7: EAP-105: Derive WLAN MAC addresses from WAN MAC
For the Edgecore EAP-105 platform, configure the 2.4GHz, 5GHz,
and 6GHz WLAN interfaces to use MAC addresses derived
from the base WAN MAC address.

Fixes: WIFI-14624

Signed-off-by: Marek Kwaczynski <marek@shasta.cloud>
2025-05-26 16:23:17 +02:00
Sundareswar
3caba52dba EAP105: Roaming failed, if MPSK (AAA server) is configured (#515)
* While Roaming the AP couldn't find the wildcard R0KH and R1KH ids,
which are required by Fast transistion.
* Issue caused by the placement of conf parser in the invalid location.

Fixes: WIFI-14544

Signed-off-by: Marek Kwaczynski <marek@shasta.cloud>
2025-05-26 16:23:17 +02:00
Ken
44bcc50815 qcom-wifi-7: Default TC fq_codel queue on GRE cause low GRE RX throughput
Fixes: WIFI-14603
Signed-off-by: Ken <xshi@actiontec.com>
2025-05-26 16:23:17 +02:00
Ken
942d7c15b4 ipq807x: WF188n/WF196 lost the certificates files after upgrade
Fixes: WIFI-14623
Signed-off-by: Ken <xshi@actiontec.com>
2025-05-26 16:23:17 +02:00
John Crispin
25be7aef1a ucentral-schema: update to latest HEAD
b4635dc add 138 to default requested DHCP options

Signed-off-by: John Crispin <john@phrozen.org>
2025-05-26 16:23:17 +02:00
43 changed files with 5299 additions and 37 deletions

View File

@@ -21,7 +21,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
target: [ 'cig_wf186h', 'cig_wf186w', 'cig_wf188n', 'cig_wf189', 'cig_wf196', 'cig_wf196', 'cybertan_eww631-a1', 'cybertan_eww631-b1', 'sonicfi_rap630w-312g', 'sonicfi_rap63xc-211g', 'sonicfi_rap630c-311g', 'sonicfi_rap630w-311g', 'sonicfi_rap630w-211g', 'sonicfi_rap650c', 'sonicfi_rap7110c-341x', 'sonicfi_rap750e-h', 'sonicfi_rap750w-311a', 'edgecore_eap101', 'edgecore_eap102', 'edgecore_eap104', 'edgecore_eap105', 'edgecore_eap111', 'edgecore_eap112', 'edgecore_oap101', 'edgecore_oap101-6e', 'edgecore_oap101e', 'edgecore_oap101e-6e', 'edgecore_oap103', 'hfcl_ion4xe', 'hfcl_ion4xi', 'hfcl_ion4x', 'hfcl_ion4x_2', 'hfcl_ion4x_3', 'hfcl_ion4xi_w', 'hfcl_ion4x_w', 'indio_um-305ax', 'senao_iap4300m', 'senao_iap2300m', 'senao_jeap6500', 'udaya_a6-id2', 'udaya_a6-od2', 'yuncore_ax820', 'yuncore_ax840', 'yuncore_fap640', 'yuncore_fap650', 'yuncore_fap655', 'emplus_wap588m', 'zyxel_nwa130be' ] target: [ 'cig_wf189h', 'cig_wf189w', 'cig_wf672', 'cig_wf186h', 'cig_wf186w', 'cig_wf188n', 'cig_wf189', 'cig_wf196', 'cig_wf196', 'cybertan_eww631-a1', 'cybertan_eww631-b1', 'sonicfi_rap630w-312g', 'sonicfi_rap63xc-211g', 'sonicfi_rap630c-311g', 'sonicfi_rap630w-311g', 'sonicfi_rap630w-211g', 'sonicfi_rap650c', 'sonicfi_rap7110c-341x', 'sonicfi_rap750e-h', 'sonicfi_rap750e-s', 'sonicfi_rap750w-311a', 'edgecore_eap101', 'edgecore_eap102', 'edgecore_eap104', 'edgecore_eap105', 'edgecore_eap111', 'edgecore_eap112', 'edgecore_oap101', 'edgecore_oap101-6e', 'edgecore_oap101e', 'edgecore_oap101e-6e', 'edgecore_oap103', 'hfcl_ion4xe', 'hfcl_ion4xi', 'hfcl_ion4x', 'hfcl_ion4x_2', 'hfcl_ion4x_3', 'hfcl_ion4xi_w', 'hfcl_ion4x_w', 'indio_um-305ax', 'senao_iap4300m', 'senao_iap2300m', 'senao_jeap6500', 'udaya_a6-id2', 'udaya_a6-od2', 'yuncore_ax820', 'yuncore_ax840', 'yuncore_fap640', 'yuncore_fap650', 'yuncore_fap655', 'emplus_wap588m', 'zyxel_nwa130be', 'sercomm_ap72tip-v4' ]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3

View File

@@ -53,6 +53,11 @@ $(call Package/ath12k-wifi-default)
TITLE:=board-2.bin for RAP750e_h TITLE:=board-2.bin for RAP750e_h
endef endef
define Package/ath12k-wifi-sonicfi-rap750e-s
$(call Package/ath12k-wifi-default)
TITLE:=board-2.bin for RAP750E-S
endef
define Package/ath12k-wifi-sonicfi-rap750w-311a define Package/ath12k-wifi-sonicfi-rap750w-311a
$(call Package/ath12k-wifi-default) $(call Package/ath12k-wifi-default)
TITLE:=board-2.bin for RAP750W_311a TITLE:=board-2.bin for RAP750W_311a
@@ -83,6 +88,11 @@ $(call Package/ath12k-wifi-default)
TITLE:=board-2.bin for NWA130BE TITLE:=board-2.bin for NWA130BE
endef endef
define Package/ath12k-wifi-cig-wf672
$(call Package/ath12k-wifi-default)
TITLE:=board-2.bin for WF672
endef
define Package/ath12k-wifi-cig-wf189/install define Package/ath12k-wifi-cig-wf189/install
$(INSTALL_DIR) $(1)/lib/firmware/ath12k/QCN92XX/hw1.0/ $(INSTALL_DIR) $(1)/lib/firmware/ath12k/QCN92XX/hw1.0/
$(INSTALL_DIR) $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/ $(INSTALL_DIR) $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/
@@ -113,6 +123,15 @@ define Package/ath12k-wifi-sonicfi-rap750e-h/install
$(INSTALL_DATA) ./ipq5332_qcn6432.regdb $(1)/lib/firmware/ath12k/QCN6432/hw1.0/regdb.bin $(INSTALL_DATA) ./ipq5332_qcn6432.regdb $(1)/lib/firmware/ath12k/QCN6432/hw1.0/regdb.bin
endef endef
define Package/ath12k-wifi-sonicfi-rap750e-s/install
$(INSTALL_DIR) $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/
$(INSTALL_DIR) $(1)/lib/firmware/ath12k/QCN6432/hw1.0/
$(INSTALL_DATA) ./board-2.bin.rap750e_s.IPQ5332 $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/board-2.bin
$(INSTALL_DATA) ./board-2.bin.rap750e_s.QCN6432 $(1)/lib/firmware/ath12k/QCN6432/hw1.0/board-2.bin
# $(INSTALL_DATA) ./ipq5332_qcn6432.regdb $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/regdb.bin
$(INSTALL_DATA) ./ipq5332_qcn6432.regdb $(1)/lib/firmware/ath12k/QCN6432/hw1.0/regdb.bin
endef
define Package/ath12k-wifi-sonicfi-rap750w-311a/install define Package/ath12k-wifi-sonicfi-rap750w-311a/install
$(INSTALL_DIR) $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/ $(INSTALL_DIR) $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/
$(INSTALL_DIR) $(1)/lib/firmware/ath12k/QCN6432/hw1.0/ $(INSTALL_DIR) $(1)/lib/firmware/ath12k/QCN6432/hw1.0/
@@ -160,13 +179,22 @@ define Package/ath12k-wifi-zyxel-nwa130be/install
$(INSTALL_DATA) ./board-2.bin.nwa130be.IPQ5332 $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/board-2.bin $(INSTALL_DATA) ./board-2.bin.nwa130be.IPQ5332 $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/board-2.bin
endef endef
define Package/ath12k-wifi-cig-wf672/install
$(INSTALL_DIR) $(1)/lib/firmware/ath12k/QCN92XX/hw1.0/
$(INSTALL_DIR) $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/
$(INSTALL_DATA) ./board-2.bin.wf672.QCN92XX $(1)/lib/firmware/ath12k/QCN92XX/hw1.0/board-2.bin
$(INSTALL_DATA) ./board-2.bin.wf672.IPQ5332 $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/board-2.bin
endef
$(eval $(call BuildPackage,ath12k-wifi-cig-wf189)) $(eval $(call BuildPackage,ath12k-wifi-cig-wf189))
$(eval $(call BuildPackage,ath12k-wifi-edgecore-eap105)) $(eval $(call BuildPackage,ath12k-wifi-edgecore-eap105))
$(eval $(call BuildPackage,ath12k-wifi-sonicfi-rap7110c-341x)) $(eval $(call BuildPackage,ath12k-wifi-sonicfi-rap7110c-341x))
$(eval $(call BuildPackage,ath12k-wifi-sonicfi-rap750e-h)) $(eval $(call BuildPackage,ath12k-wifi-sonicfi-rap750e-h))
$(eval $(call BuildPackage,ath12k-wifi-sonicfi-rap750e-s))
$(eval $(call BuildPackage,ath12k-wifi-sonicfi-rap750w-311a)) $(eval $(call BuildPackage,ath12k-wifi-sonicfi-rap750w-311a))
$(eval $(call BuildPackage,ath12k-wifi-cig-wf189w)) $(eval $(call BuildPackage,ath12k-wifi-cig-wf189w))
$(eval $(call BuildPackage,ath12k-wifi-cig-wf189h)) $(eval $(call BuildPackage,ath12k-wifi-cig-wf189h))
$(eval $(call BuildPackage,ath12k-wifi-sercomm-ap72tip)) $(eval $(call BuildPackage,ath12k-wifi-sercomm-ap72tip))
$(eval $(call BuildPackage,ath12k-wifi-sercomm-ap72tip-v4)) $(eval $(call BuildPackage,ath12k-wifi-sercomm-ap72tip-v4))
$(eval $(call BuildPackage,ath12k-wifi-zyxel-nwa130be)) $(eval $(call BuildPackage,ath12k-wifi-zyxel-nwa130be))
$(eval $(call BuildPackage,ath12k-wifi-cig-wf672))

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,30 @@
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=cig-wifi-mode-switch
PKG_RELEASE:=1
PKG_LICENSE:=GPL-2.0
include $(INCLUDE_DIR)/package.mk
define KernelPackage/cig-wifi-mode-sw
SUBMENU:=Other modules
TITLE:=CIG wifi mode switch tool
FILES:=$(PKG_BUILD_DIR)/cig_rf_switch.ko
AUTOLOAD:=$(call AutoLoad,60,cig_rf_switch)
endef
define KernelPackage/cig-wifi-mode-sw/description
CIG wifi mode switch tool for configure wifi mode 2 bands or 3 bands
endef
define Build/Compile
$(KERNEL_MAKE) M="$(PKG_BUILD_DIR)" modules
endef
define KernelPackage/cig-wifi-mode-sw/install
$(INSTALL_DIR) $(1)/usr/sbin/
$(INSTALL_BIN) ./files/cig_wifi_mode_sw $(1)/usr/sbin/cig_wms
endef
$(eval $(call KernelPackage,cig-wifi-mode-sw))

View File

@@ -0,0 +1,11 @@
#!/bin/sh
band=$1
if [ $band -eq 2 ] || [ $band -eq 3 ]; then
echo $band > /proc/rf_switch
echo "reboot for switch wifi mode 2/3 bands"
sleep 1
reboot
else
echo "error band param"
fi

View File

@@ -0,0 +1 @@
obj-m += cig_rf_switch.o

View File

@@ -0,0 +1,276 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/mmc/core.h>
#include <linux/mmc/host.h>
#include <linux/major.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/card.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/list.h>
#include <linux/pagemap.h>
#define PROC_NAME "rf_switch"
#define PARTITION_NAME "RF_SWITCH"
#define MAX_DATA_SIZE 2
#define MAX_MMC_DEVICE 2
struct block_device *target_bdev = NULL;
static char current_value[MAX_DATA_SIZE] = "3";
static unsigned int __blkdev_sectors_to_bio_pages(sector_t nr_sects)
{
sector_t pages = DIV_ROUND_UP_SECTOR_T(nr_sects, PAGE_SIZE / 512);
return min(pages, (sector_t)BIO_MAX_VECS);
}
struct block_device *find_mmc_partition(void)
{
struct gendisk *disk = NULL;
unsigned long idx;
struct block_device *bdev = NULL;
unsigned int i;
for (i = 0; i < MAX_MMC_DEVICE; i++) {
bdev = blkdev_get_by_dev(MKDEV(MMC_BLOCK_MAJOR, i * CONFIG_MMC_BLOCK_MINORS), FMODE_READ | FMODE_WRITE, NULL);
if (IS_ERR(bdev)) {
pr_err("Failed to open MMC device %u: %ld\n", i, PTR_ERR(bdev));
continue;
}
disk = bdev->bd_disk;
if (!disk) {
blkdev_put(bdev, FMODE_READ | FMODE_WRITE);
continue;
}
xa_for_each_start(&disk->part_tbl, idx, bdev, 1) {
if (bdev->bd_meta_info && strcmp(bdev->bd_meta_info->volname, PARTITION_NAME) == 0) {
pr_info("Found RF_SWITCH partition at device %u\n", i);
return bdev;
}
}
blkdev_put(bdev, FMODE_READ | FMODE_WRITE);
}
return NULL;
}
int read_string_from_emmc(struct block_device *bdev, size_t max_length, char *buffer)
{
struct bio *bio;
struct page *page;
int err = 0;
void *data;
page = alloc_page(GFP_KERNEL);
if (!page) {
return -ENOMEM;
}
bio = bio_alloc(bdev, __blkdev_sectors_to_bio_pages(1), REQ_OP_READ, GFP_KERNEL);
bio_set_dev(bio, bdev);
bio->bi_iter.bi_sector = 0;
bio_add_page(bio, page, PAGE_SIZE, 0);
submit_bio_wait(bio);
if (bio->bi_status) {
err = -EIO;
goto out_bio;
}
data = kmap(page);
kunmap(page);
memcpy(buffer, data, max_length - 1);
buffer[max_length - 1] = '\0';
out_bio:
bio_put(bio);
__free_page(page);
return err;
}
static int rf_switch_proc_show(struct seq_file *m, void *v)
{
char buffer[MAX_DATA_SIZE] = {0};
int ret;
ret = read_string_from_emmc(target_bdev, MAX_DATA_SIZE, buffer);
if (ret) {
seq_printf(m, "%s\n", current_value);
return 0;
}
if (strcmp(buffer, "2") == 0 || strcmp(buffer, "3") == 0) {
strncpy(current_value, buffer, MAX_DATA_SIZE);
seq_printf(m, "%s\n", current_value);
} else {
seq_printf(m, "%s\n", current_value);
}
return 0;
}
static int blkdev_issue_write(struct block_device *bdev, sector_t sector, sector_t nr_sects, gfp_t gfp_mask, struct page *page)
{
int ret = 0;
sector_t bs_mask;
struct bio *bio;
int bi_size = 0;
unsigned int sz;
if (bdev_read_only(bdev))
return -EPERM;
bs_mask = (bdev_logical_block_size(bdev) >> 9) - 1;
if ((sector | nr_sects) & bs_mask)
return -EINVAL;
bio = bio_alloc(bdev, __blkdev_sectors_to_bio_pages(nr_sects),
REQ_OP_WRITE, gfp_mask);
if (!bio) {
pr_err("Couldn't alloc bio");
return -1;
}
bio->bi_iter.bi_sector = sector;
bio_set_dev(bio, bdev);
bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
sz = bdev_logical_block_size(bdev);
bi_size = bio_add_page(bio, page, sz, 0);
if(bi_size != sz) {
pr_err("Couldn't add page to the log block");
goto error;
}
if (bio)
{
ret = submit_bio_wait(bio);
bio_put(bio);
}
return ret;
error:
bio_put(bio);
return -1;
}
static int write_data_to_emmc(struct block_device *bdev, const unsigned char *data, unsigned char fill_byte)
{
struct page *page;
void *ptr;
sector_t sector_offset = 0;
int ret = 0;
if (!bdev || !data)
return -EINVAL;
page = alloc_page(GFP_KERNEL);
if (!page) {
pr_err("Failed to allocate page\n");
return -ENOMEM;
}
ptr = kmap_atomic(page);
memcpy(ptr, data, MAX_DATA_SIZE);
memset(ptr + MAX_DATA_SIZE, fill_byte, 512-MAX_DATA_SIZE);
kunmap_atomic(ptr);
ret = blkdev_issue_write(bdev, sector_offset , 1 ,GFP_ATOMIC, page);
if (ret) {
pr_err("Failed to write to eMMC at offset 0: %d\n", ret);
__free_page(page);
return ret;
}
sync_blockdev(bdev);
__free_page(page);
return ret;
}
static ssize_t rf_switch_proc_write(struct file *file, const char __user *user_buffer, size_t count, loff_t *ppos)
{
unsigned char buffer[MAX_DATA_SIZE] = {0};
int ret;
if (count != MAX_DATA_SIZE)
return -EINVAL;
if (copy_from_user(buffer, user_buffer, count))
return -EFAULT;
buffer[count -1] = '\0';
if (strcmp(buffer, "2") != 0 && strcmp(buffer, "3") != 0) {
pr_err("Invalid value: %s. Only '2' or '3' are allowed.\n", buffer);
return -EINVAL;
}
ret = write_data_to_emmc(target_bdev, buffer, 0xFF);
if (ret) {
pr_err("Failed to write to RF_SWITCH\n");
return ret;
}
strncpy(current_value, buffer, MAX_DATA_SIZE);
return count;
}
static int rf_switch_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, rf_switch_proc_show, NULL);
}
static const struct proc_ops rf_switch_proc_fops = {
.proc_open = rf_switch_proc_open,
.proc_read = seq_read,
.proc_write = rf_switch_proc_write,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
static int __init rf_switch_init(void)
{
target_bdev = find_mmc_partition();
if (!target_bdev) {
pr_err("Failed to find eMMC card or RF_SWITCH partition\n");
return -ENOMEM;
}
if (!proc_create(PROC_NAME, 0666, NULL, &rf_switch_proc_fops)) {
pr_err("Failed to create proc entry\n");
return -ENOMEM;
}
pr_info("RF_SWITCH partition proc interface created\n");
return 0;
}
static void __exit rf_switch_exit(void)
{
if (target_bdev) {
blkdev_put(target_bdev, FMODE_READ | FMODE_WRITE);
target_bdev = NULL;
}
remove_proc_entry(PROC_NAME, NULL);
pr_info("RF_SWITCH partition proc interface removed\n");
}
module_init(rf_switch_init);
module_exit(rf_switch_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yunxiang Huang");
MODULE_DESCRIPTION("RF_SWITCH partition read/write driver");

View File

@@ -1,3 +1,4 @@
unchanged:
--- a/hostapd/config_file.c --- a/hostapd/config_file.c
+++ b/hostapd/config_file.c +++ b/hostapd/config_file.c
@@ -3003,6 +3003,8 @@ static int hostapd_config_fill(struct ho @@ -3003,6 +3003,8 @@ static int hostapd_config_fill(struct ho
@@ -9,12 +10,10 @@
#endif /* CONFIG_IEEE80211R_AP */ #endif /* CONFIG_IEEE80211R_AP */
#ifndef CONFIG_NO_CTRL_IFACE #ifndef CONFIG_NO_CTRL_IFACE
} else if (os_strcmp(buf, "ctrl_interface") == 0) { } else if (os_strcmp(buf, "ctrl_interface") == 0) {
@@ -4958,8 +4960,22 @@ int hostapd_set_iface(struct hostapd_con @@ -4982,6 +4982,19 @@ struct hostapd_config * hostapd_config_r
return -1; fclose(f);
}
- for (i = 0; i < conf->num_bss; i++) for (i = 0; i < conf->num_bss; i++) {
+ for (i = 0; i < conf->num_bss; i++) {
+ if (*conf->bss[i]->ft_key) { + if (*conf->bss[i]->ft_key) {
+ u8 buffer[128]; + u8 buffer[128];
+ sprintf(buffer, "%02X:%02X:%02X:%02X:%02X:%02X %02X%02X%02X%02X%02X%02X %s", MAC2STR(conf->bss[i]->bssid), MAC2STR(conf->bss[i]->bssid), conf->bss[i]->ft_key); + sprintf(buffer, "%02X:%02X:%02X:%02X:%02X:%02X %02X%02X%02X%02X%02X%02X %s", MAC2STR(conf->bss[i]->bssid), MAC2STR(conf->bss[i]->bssid), conf->bss[i]->ft_key);
@@ -25,14 +24,12 @@
+ add_r0kh(conf->bss[i], buffer); + add_r0kh(conf->bss[i], buffer);
+ sprintf(buffer, "00:00:00:00:00:00 00:00:00:00:00:00 %s", conf->bss[i]->ft_key); + sprintf(buffer, "00:00:00:00:00:00 00:00:00:00:00:00 %s", conf->bss[i]->ft_key);
+ add_r1kh(conf->bss[i], buffer); + add_r1kh(conf->bss[i], buffer);
+ hexstr2bin(conf->bss[i]->bssid, conf->bss[i]->r1_key_holder, FT_R1KH_ID_LEN); + hexstr2bin(conf->bss[i]->bssid, conf->bss[i]->r1_key_holder, FT_R1KH_ID_LEN);
+ conf->bss[i]->r0_key_holder_bssid = 1; + conf->bss[i]->r0_key_holder_bssid = 1;
+ } + }
hostapd_set_security_params(conf->bss[i], 0); hostapd_set_security_params(conf->bss[i], 1);
+ } #ifdef CONFIG_IEEE80211BE
if (conf->ieee80211be && conf->bss[i]->ieee80211w > 0
if (hostapd_config_check(conf, 0)) {
wpa_printf(MSG_ERROR, "Configuration check failed");
--- a/src/ap/ap_config.h --- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h +++ b/src/ap/ap_config.h
@@ -398,6 +398,7 @@ struct hostapd_bss_config { @@ -398,6 +398,7 @@ struct hostapd_bss_config {

View File

@@ -785,6 +785,7 @@ int hostapd_ucode_sta_auth(struct hostapd_data *hapd, struct sta_info *sta)
void hostapd_ucode_sta_connected(struct hostapd_data *hapd, struct sta_info *sta) void hostapd_ucode_sta_connected(struct hostapd_data *hapd, struct sta_info *sta)
{ {
struct hostapd_sta_wpa_psk_short *psk = sta->psk;
char addr[sizeof(MACSTR)]; char addr[sizeof(MACSTR)];
uc_value_t *val, *cur; uc_value_t *val, *cur;
int ret = 0; int ret = 0;
@@ -801,6 +802,8 @@ void hostapd_ucode_sta_connected(struct hostapd_data *hapd, struct sta_info *sta
val = ucv_object_new(vm); val = ucv_object_new(vm);
if (sta->psk_idx) if (sta->psk_idx)
ucv_object_add(val, "psk_idx", ucv_int64_new(sta->psk_idx - 1)); ucv_object_add(val, "psk_idx", ucv_int64_new(sta->psk_idx - 1));
if (sta->psk)
ucv_object_add(val, "psk", ucv_string_new(sta->psk->passphrase));
uc_value_push(ucv_get(val)); uc_value_push(ucv_get(val));
val = wpa_ucode_call(3); val = wpa_ucode_call(3);

View File

@@ -15,6 +15,7 @@ sercomm,ap72tip)
;; ;;
sonicfi,rap7110c-341x|\ sonicfi,rap7110c-341x|\
sonicfi,rap750e-h|\ sonicfi,rap750e-h|\
sonicfi,rap750e-s|\
sonicfi,rap750w-311a) sonicfi,rap750w-311a)
ucidef_set_led_default "power" "POWER" "pwm:blue" "on" ucidef_set_led_default "power" "POWER" "pwm:blue" "on"
;; ;;

View File

@@ -13,13 +13,15 @@ ipq53xx_setup_interfaces()
ucidef_set_interfaces_lan_wan "eth1 eth2 eth3 eth4 eth5" "eth0" ucidef_set_interfaces_lan_wan "eth1 eth2 eth3 eth4 eth5" "eth0"
;; ;;
cig,wf189|\ cig,wf189|\
cig,wf672|\
edgecore,eap105|\ edgecore,eap105|\
sercomm,ap72tip|\ sercomm,ap72tip|\
sonicfi,rap750w-311a) sonicfi,rap750w-311a)
ucidef_set_interfaces_lan_wan "eth1" "eth0" ucidef_set_interfaces_lan_wan "eth1" "eth0"
;; ;;
sonicfi,rap7110c-341x|\ sonicfi,rap7110c-341x|\
sonicfi,rap750e-h) sonicfi,rap750e-h|\
sonicfi,rap750e-s)
ucidef_set_interfaces_lan_wan "" "eth0" ucidef_set_interfaces_lan_wan "" "eth0"
;; ;;
cig,wf189w) cig,wf189w)
@@ -43,21 +45,35 @@ qcom_setup_macs()
{ {
local board="$1" local board="$1"
case $board in case $board in
cig,wf189w|\ cig,wf189w|\
cig,wf189h|\ cig,wf189h|\
cig,wf189) cig,wf189)
mtd=$(find_mtd_chardev "0:APPSBLENV") mtd=$(find_mtd_chardev "0:APPSBLENV")
[ -z "$mtd" ] && return; [ -z "$mtd" ] && return;
mac=$(grep eth1addr= $mtd | cut -d= -f2) mac=$(grep eth1addr= $mtd | cut -d= -f2)
[ -z "$mac" ] && return; [ -z "$mac" ] && return;
wan_mac=$(macaddr_canonicalize $mac) wan_mac=$(macaddr_canonicalize $mac)
lan_mac=$(macaddr_add "$wan_mac" 1) lan_mac=$(macaddr_add "$wan_mac" 1)
ucidef_set_network_device_mac eth0 $wan_mac ucidef_set_network_device_mac eth0 $wan_mac
ucidef_set_network_device_mac eth1 $lan_mac ucidef_set_network_device_mac eth1 $lan_mac
ucidef_set_label_macaddr $wan_mac ucidef_set_label_macaddr $wan_mac
ucidef_set_wireless_macaddr_base 2g $(macaddr_add "$wan_mac" 2) ucidef_set_wireless_macaddr_base 2g $(macaddr_add "$wan_mac" 2)
ucidef_set_wireless_macaddr_base 5g $(macaddr_add "$wan_mac" 3) ucidef_set_wireless_macaddr_base 5g $(macaddr_add "$wan_mac" 3)
ucidef_set_wireless_macaddr_base 6g $(macaddr_add "$wan_mac" 4) ucidef_set_wireless_macaddr_base 6g $(macaddr_add "$wan_mac" 4)
;;
cig,wf672)
mmc=$(find_mmc_part "0:APPSBLENV")
[ -z "$mmc" ] && return;
mac=$(grep eth1addr= $mmc | cut -d= -f2)
[ -z "$mac" ] && return;
wan_mac=$(macaddr_canonicalize $mac)
lan_mac=$(macaddr_add "$wan_mac" 1)
ucidef_set_network_device_mac eth0 $wan_mac
ucidef_set_network_device_mac eth1 $lan_mac
ucidef_set_label_macaddr $wan_mac
ucidef_set_wireless_macaddr_base 2g $(macaddr_add "$wan_mac" 2)
ucidef_set_wireless_macaddr_base 5g $(macaddr_add "$wan_mac" 3)
ucidef_set_wireless_macaddr_base 6g $(macaddr_add "$wan_mac" 4)
;; ;;
sercomm,ap72tip) sercomm,ap72tip)
wan_mac=$(cat /sys/class/net/eth0/address) wan_mac=$(cat /sys/class/net/eth0/address)
@@ -69,9 +85,13 @@ qcom_setup_macs()
edgecore,eap105) edgecore,eap105)
wan_mac=$(cat /sys/class/net/eth0/address) wan_mac=$(cat /sys/class/net/eth0/address)
lan_mac=$(macaddr_add "$wan_mac" 1) lan_mac=$(macaddr_add "$wan_mac" 1)
ucidef_set_wireless_macaddr_base 2g $(macaddr_add "$wan_mac" 2)
ucidef_set_wireless_macaddr_base 5g $(macaddr_add "$wan_mac" 3)
ucidef_set_wireless_macaddr_base 6g $(macaddr_add "$wan_mac" 4)
;; ;;
sonicfi,rap7110c-341x|\ sonicfi,rap7110c-341x|\
sonicfi,rap750e-h) sonicfi,rap750e-h|\
sonicfi,rap750e-s)
wan_mac=$(cat /sys/class/net/eth0/address) wan_mac=$(cat /sys/class/net/eth0/address)
ucidef_set_wireless_macaddr_base 2g $(macaddr_add "$wan_mac" 1) ucidef_set_wireless_macaddr_base 2g $(macaddr_add "$wan_mac" 1)
ucidef_set_wireless_macaddr_base 5g $(macaddr_add "$wan_mac" 2) ucidef_set_wireless_macaddr_base 5g $(macaddr_add "$wan_mac" 2)

View File

@@ -23,6 +23,39 @@ caldata_extract() {
caldata_die "failed to extract calibration data from $mtd" caldata_die "failed to extract calibration data from $mtd"
} }
cig_ipq5322_cal() {
local ext_ant=0
[ -f /sys/firmware/devicetree/base/soc@0/wifi@c0000000/ext_antenna ] && ext_ant=1
if [ "$ext_ant" = "0" ]; then
caldata_extract_mmc "0:ART" 0x1000 0x20000
else
caldata_extract_mmc "0:ART" 0xbd800 0x20000
fi
}
cig_qcn92xx_cal() {
local bands=$(cat /proc/rf_switch)
local ext_ant=0
[ -f /sys/firmware/devicetree/base/soc@0/wifi@c0000000/ext_antenna ] && ext_ant=1
if [ "$bands" = "2" ]; then
if [ "$ext_ant" = "0" ]; then
caldata_extract_mmc "0:ART" 0x8b800 0x2d000
else
caldata_extract_mmc "0:ART" 0xe3000 0x2d000
fi
else
if [ "$ext_ant" = "0" ]; then
caldata_extract_mmc "0:ART" 0x58800 0x2d000
else
caldata_extract_mmc "0:ART" 0x115000 0x2d000
fi
fi
}
board=$(board_name) board=$(board_name)
case "$FIRMWARE" in case "$FIRMWARE" in
ath12k/IPQ5332/hw1.0/caldata.bin) ath12k/IPQ5332/hw1.0/caldata.bin)
@@ -36,10 +69,14 @@ ath12k/IPQ5332/hw1.0/caldata.bin)
zyxel,nwa130be) zyxel,nwa130be)
caldata_extract "0:ART" 0x1000 0x20000 caldata_extract "0:ART" 0x1000 0x20000
;; ;;
cig,wf672)
cig_ipq5322_cal
;;
sonicfi,rap7110c-341x) sonicfi,rap7110c-341x)
caldata_extract_mmc "0:ART" 0x1000 0xF800 caldata_extract_mmc "0:ART" 0x1000 0xF800
;; ;;
sonicfi,rap750e-h|\ sonicfi,rap750e-h|\
sonicfi,rap750e-s|\
sonicfi,rap750w-311a) sonicfi,rap750w-311a)
caldata_extract "0:ART" 0x1000 0xf800 caldata_extract "0:ART" 0x1000 0xf800
;; ;;
@@ -54,6 +91,9 @@ ath12k/QCN92XX/hw1.0/cal-pci-0001:01:00.0.bin)
zyxel,nwa130be) zyxel,nwa130be)
caldata_extract "0:ART" 0x58800 0x2d000 caldata_extract "0:ART" 0x58800 0x2d000
;; ;;
cig,wf672)
cig_qcn92xx_cal
;;
sonicfi,rap7110c-341x) sonicfi,rap7110c-341x)
caldata_extract_mmc "0:ART" 0x58800 0x2d000 caldata_extract_mmc "0:ART" 0x58800 0x2d000
;; ;;
@@ -62,6 +102,7 @@ ath12k/QCN92XX/hw1.0/cal-pci-0001:01:00.0.bin)
ath12k/QCN6432/hw1.0/caldata_1.bin) ath12k/QCN6432/hw1.0/caldata_1.bin)
case "$board" in case "$board" in
sonicfi,rap750e-h|\ sonicfi,rap750e-h|\
sonicfi,rap750e-s|\
sonicfi,rap750w-311a) sonicfi,rap750w-311a)
caldata_extract "0:ART" 0x12800 0x18800 caldata_extract "0:ART" 0x12800 0x18800
;; ;;

View File

@@ -0,0 +1,20 @@
# /etc/hotplug.d/iface/85-greqos
[ "$ACTION" == "ifup" ] || exit 0
. /lib/functions.sh
case "$(board_name)" in
cig,wf189|\
cig,wf189w|\
cig,wf189h|\
cig,wf672)
case "$INTERFACE" in
gre*)
dev=$(ubus call network.interface.$INTERFACE status | jsonfilter -e '@.l3_device')
[ -n "$dev" ] && {
tc qdisc del dev $dev root 2>/dev/null
tc qdisc add dev $dev root noqueue
}
;;
esac
esac

View File

@@ -57,6 +57,52 @@ sonicfi_dualimage_check() {
fi fi
} }
spi_nor_emmc_do_upgrade_bootconfig() {
local tar_file="$1"
local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$')
board_dir=${board_dir%/}
[ -f /proc/boot_info/bootconfig0/getbinary_bootconfig ] || {
echo "bootconfig does not exist"
exit
}
CI_ROOTPART="$(cat /proc/boot_info/bootconfig0/rootfs/upgradepartition)"
CI_KERNPART="$(cat /proc/boot_info/bootconfig0/0:HLOS/upgradepartition)"
[ -n "$CI_KERNPART" -a -n "$CI_ROOTPART" ] || {
echo "kernel or rootfs partition is unknown"
exit
}
local primary="0"
[ "$(cat /proc/boot_info/bootconfig0/rootfs/primaryboot)" = "0" ] && primary="1"
echo "$primary" > /proc/boot_info/bootconfig0/rootfs/primaryboot 2>/dev/null
echo "$primary" > /proc/boot_info/bootconfig0/0:HLOS/primaryboot 2>/dev/null
cp /proc/boot_info/bootconfig0/getbinary_bootconfig /tmp/bootconfig
do_flash_emmc $tar_file $CI_KERNPART $board_dir kernel
do_flash_emmc $tar_file $CI_ROOTPART $board_dir root
local emmcblock="$(find_mmc_part "rootfs_data")"
if [ -e "$emmcblock" ]; then
mkfs.ext4 -F "$emmcblock"
fi
for part in "0:BOOTCONFIG" "0:BOOTCONFIG1"; do
local mtdchar=$(echo $(find_mtd_chardev $part) | sed 's/^.\{5\}//')
if [ -n "$mtdchar" ]; then
echo start to update $mtdchar
mtd -qq write /proc/boot_info/bootconfig0/getbinary_bootconfig "/dev/${mtdchar}" 2>/dev/null && echo update mtd $mtdchar
else
emmcblock=$(find_mmc_part $part)
echo erase ${emmcblock}
dd if=/dev/zero of=${emmcblock} 2> /dev/null
echo update $emmcblock
dd if=/tmp/bootconfig of=${emmcblock} 2> /dev/null
fi
done
}
emmc_do_upgrade() { emmc_do_upgrade() {
local tar_file="$1" local tar_file="$1"
local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$') local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$')
@@ -86,6 +132,8 @@ platform_do_upgrade() {
board=$(board_name) board=$(board_name)
case $board in case $board in
sercomm,ap72tip-v4|\
sercomm,ap72tip|\
cig,wf189w|\ cig,wf189w|\
cig,wf189h|\ cig,wf189h|\
cig,wf189) cig,wf189)
@@ -98,6 +146,9 @@ platform_do_upgrade() {
fi fi
nand_upgrade_tar "$1" nand_upgrade_tar "$1"
;; ;;
cig,wf672)
spi_nor_emmc_do_upgrade_bootconfig $1
;;
edgecore,eap105) edgecore,eap105)
if [ "$(find_mtd_chardev rootfs)" ]; then if [ "$(find_mtd_chardev rootfs)" ]; then
CI_UBIPART="rootfs" CI_UBIPART="rootfs"
@@ -117,14 +168,11 @@ platform_do_upgrade() {
emmc_do_upgrade "$1" emmc_do_upgrade "$1"
;; ;;
sonicfi,rap750e-h|\ sonicfi,rap750e-h|\
sonicfi,rap750e-s|\
sonicfi,rap750w-311a) sonicfi,rap750w-311a)
sonicfi_dualimage_check sonicfi_dualimage_check
nand_upgrade_tar "$1" nand_upgrade_tar "$1"
;; ;;
sercomm,ap72tip-v4|\
sercomm,ap72tip)
nand_upgrade_tar "$1"
;;
zyxel,nwa130be) zyxel,nwa130be)
nand_upgrade_tar "$1" nand_upgrade_tar "$1"
;; ;;

View File

@@ -1223,3 +1223,5 @@ CONFIG_PSTORE=y
CONFIG_PSTORE_CONSOLE=y CONFIG_PSTORE_CONSOLE=y
CONFIG_PSTORE_PMSG=y CONFIG_PSTORE_PMSG=y
CONFIG_PSTORE_RAM=y CONFIG_PSTORE_RAM=y
# CONFIG_RTL8221D_PHY is not set
# CONFIG_INPUT_LSM303AGR is not set

View File

@@ -0,0 +1,548 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
* IPQ5332 RDP468 board device tree source
*
* Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
/dts-v1/;
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/leds/common.h>
#include "ipq5332.dtsi"
#include "ipq5332-default-memory.dtsi"
/ {
model = "CIG WF672";
compatible = "cig,wf672", "qcom,ipq5332-rdp468", "qcom,ipq5332";
aliases {
serial0 = &blsp1_uart0;
serial1 = &blsp1_uart1;
ethernet0 = "/soc/dp1";
ethernet1 = "/soc/dp2";
led-boot = &led_power_green;
led-failsafe = &led_power_red;
led-running = &led_power_green;
led-upgrade = &led_power_green;
};
chosen {
stdout-path = "serial0";
};
soc@0 {
mdio:mdio@90000 {
pinctrl-0 = <&mdio1_pins>;
pinctrl-names = "default";
/*gpio51 for manhattan reset*/
phy-reset-gpio = <&tlmm 21 GPIO_ACTIVE_LOW>;
phyaddr_fixup = <0xC90F018>;
uniphyaddr_fixup = <0xC90F014>;
mdio_clk_fixup; /* MDIO clock sequence fix up flag */
status = "okay";
phy0: ethernet-phy@0 {
reg = <1>;
compatible ="ethernet-phy-ieee802.3-c45";
fixup;
};
phy1: ethernet-phy@1 {
reg = <30>;
fixup;
};
};
ess-instance {
num_devices = <0x1>;
ess-switch@3a000000 {
switch_cpu_bmp = <0x1>; /* cpu port bitmap */
switch_lan_bmp = <0x2>; /* lan port bitmap */
switch_wan_bmp = <0x4>; /* wan port bitmap */
switch_mac_mode = <0xc>; /* mac mode for uniphy instance0*/
switch_mac_mode1 = <0xe>; /* mac mode for uniphy instance1*/
switch_mac_mode2 = <0xff>; /* mac mode for uniphy instance2*/
qcom,port_phyinfo {
port@0 {
port_id = <1>;
phy_address = <1>;
ethernet-phy-ieee802.3-c45;
forced-speed = <2500>;
forced-duplex = <1>;
mdiobus = <&mdio>;
};
port@1 {
port_id = <2>;
phy_address = <30>;
phy_i2c_address =<30>;
phy-i2c-mode;
sfp_rx_los_pin = <&tlmm 43 0>;
sfp_mod_present_pin = <&tlmm 45 0>;
sfp_tx_dis_pin = <&extgpio 11 0>;
media-type = "sfp"; /* fiber mode */
};
};
};
};
dp2 {
device_type = "network";
compatible = "qcom,nss-dp";
qcom,id = <1>;
reg = <0x3a500000 0x4000>;
qcom,mactype = <1>;
local-mac-address = [000000000000];
mdio-bus = <&mdio>;
qcom,phy-mdio-addr = <1>;
qcom,link-poll = <1>;
phy-mode = "sgmii";
};
gmac2:dp1 {
device_type = "network";
compatible = "qcom,nss-dp";
qcom,id = <2>;
reg = <0x3a504000 0x4000>;
qcom,mactype = <1>;
local-mac-address = [000000000000];
qcom,phy-mdio-addr = <30>;
qcom,link-poll = <1>;
phy-mode = "sgmii";
};
x5-cpe {
compatible = "x55-poweron";
pwykey = <&extgpio2 13 0>;
status = "ok";
};
/* EDMA host driver configuration for the board */
edma@3ab00000 {
qcom,txdesc-ring-start = <4>; /* Tx desc ring start ID */
qcom,txdesc-rings = <12>; /* Total number of Tx desc rings to be provisioned */
qcom,mht-txdesc-rings = <8>; /* Extra Tx desc rings to be provisioned for MHT SW ports */
qcom,txcmpl-ring-start = <4>; /* Tx complete ring start ID */
qcom,txcmpl-rings = <12>; /* Total number of Tx complete rings to be provisioned */
qcom,mht-txcmpl-rings = <8>; /* Extra Tx complete rings to be provisioned for mht sw ports. */
qcom,rxfill-ring-start = <4>; /* Rx fill ring start ID */
qcom,rxfill-rings = <4>; /* Total number of Rx fill rings to be provisioned */
qcom,rxdesc-ring-start = <12>; /* Rx desc ring start ID */
qcom,rxdesc-rings = <4>; /* Total number of Rx desc rings to be provisioned */
qcom,rx-page-mode = <0>; /* Rx fill ring page mode */
qcom,tx-map-priority-level = <1>; /* Tx priority level per port */
qcom,rx-map-priority-level = <1>; /* Rx priority level per core */
qcom,ppeds-num = <2>; /* Number of PPEDS nodes */
/* PPE-DS node format: <Rx-fill Tx-cmpl Rx Tx Queue-base Queue-count> */
qcom,ppeds-map = <1 1 1 1 32 8>, /* PPEDS Node#0 ring and queue map */
<2 2 2 2 40 8>; /* PPEDS Node#1 ring and queue map */
qcom,txdesc-map = <8 9 10 11>, /* Port0 per-core Tx ring map */
<12 13 14 15>, /* MHT-Port1 per-core Tx ring map */
<4 5 6 7>, /* MHT-Port2 per-core Tx ring map/packets from vp*/
<16 17 18 19>, /* MHT-Port3 per-core Tx ring map */
<20 21 22 23>; /* MHT-Port4 per-core Tx ring map */
qcom,txdesc-fc-grp-map = <1 2 3 4 5>; /* Per GMAC flow control group map */
qcom,rxfill-map = <4 5 6 7>; /* Per-core Rx fill ring map */
qcom,rxdesc-map = <12 13 14 15>; /* Per-core Rx desc ring map */
qcom,rx-queue-start = <0>; /* Rx queue start */
qcom,rx-ring-queue-map = <0 8 16 24>, /* Priority 0 queues per-core Rx ring map */
<1 9 17 25>, /* Priority 1 queues per-core Rx ring map */
<2 10 18 26>, /* Priority 2 queues per-core Rx ring map */
<3 11 19 27>, /* Priority 3 queues per-core Rx ring map */
<4 12 20 28>, /* Priority 4 queues per-core Rx ring map */
<5 13 21 29>, /* Priority 5 queues per-core Rx ring map */
<6 14 22 30>, /* Priority 6 queues per-core Rx ring map */
<7 15 23 31>; /* Priority 7 queues per-core Rx ring map */
interrupts = <0 163 4>, /* Tx complete ring id #4 IRQ info */
<0 164 4>, /* Tx complete ring id #5 IRQ info */
<0 165 4>, /* Tx complete ring id #6 IRQ info */
<0 166 4>, /* Tx complete ring id #7 IRQ info */
<0 167 4>, /* Tx complete ring id #8 IRQ info */
<0 168 4>, /* Tx complete ring id #9 IRQ info */
<0 169 4>, /* Tx complete ring id #10 IRQ info */
<0 170 4>, /* Tx complete ring id #11 IRQ info */
<0 171 4>, /* Tx complete ring id #12 IRQ info */
<0 172 4>, /* Tx complete ring id #13 IRQ info */
<0 173 4>, /* Tx complete ring id #14 IRQ info */
<0 174 4>, /* Tx complete ring id #15 IRQ info */
<0 139 4>, /* Rx desc ring id #12 IRQ info */
<0 140 4>, /* Rx desc ring id #13 IRQ info */
<0 141 4>, /* Rx desc ring id #14 IRQ info */
<0 142 4>, /* Rx desc ring id #15 IRQ info */
<0 191 4>, /* Misc error IRQ info */
<0 160 4>, /* PPEDS Node #1(TxComp ring id #1) TxComplete IRQ info */
<0 128 4>, /* PPEDS Node #1(Rx Desc ring id #1) Rx Desc IRQ info */
<0 152 4>, /* PPEDS Node #1(RxFill Desc ring id #1) Rx Fill IRQ info */
<0 161 4>, /* PPEDS Node #2(TxComp ring id #2) TxComplete IRQ info */
<0 129 4>, /* PPEDS Node #2(Rx Desc ring id #2) Rx Desc IRQ info */
<0 153 4>, /* PPEDS Node #2(RxFill Desc ring id #2) Rx Fill IRQ info */
<0 175 4>, /* MHT port Tx complete ring id #16 IRQ info */
<0 176 4>, /* MHT port Tx complete ring id #17 IRQ info */
<0 177 4>, /* MHT port Tx complete ring id #18 IRQ info */
<0 178 4>, /* MHT port Tx complete ring id #19 IRQ info */
<0 179 4>, /* MHT port Tx complete ring id #20 IRQ info */
<0 180 4>, /* MHT port Tx complete ring id #21 IRQ info */
<0 181 4>, /* MHT port Tx complete ring id #22 IRQ info */
<0 182 4>; /* MHT port Tx complete ring id #23 IRQ info */
};
pwmleds {
compatible = "pwm-leds";
led_power_red:red {
label = "pwm:red";
pwms = <&pwm 3 1250000>;
max-brightness = <160>;
linux,default-trigger = "none";
default-state = "off";
};
led_power_green:green {
label = "pwm:green";
pwms = <&pwm 2 1250000>;
max-brightness = <160>;
linux,default-trigger = "none";
default-state = "off";
};
led_power_blue: blue {
label = "pwm:blue";
pwms = <&pwm 1 1250000>;
max-brightness = <160>;
linux,default-trigger = "none";
default-state = "off";
};
};
gpio_keys {
compatible = "gpio-keys";
pinctrl-0 = <&button_pins>;
pinctrl-names = "default";
status = "okay";
button@1 {
label = "rst";
linux,code = <KEY_RESTART>;
gpios = <&tlmm 24 GPIO_ACTIVE_LOW>;
linux,input-type = <1>;
debounce-interval = <60>;
};
};
wsi: wsi {
id = <0>;
num_chip = <2>;
status = "okay";
chip_info = <0 1 1>,
<1 1 0>;
};
};
};
&wifi0 {
led-gpio = <&tlmm 36 GPIO_ACTIVE_HIGH>;
qcom,rproc = <&q6_wcss_pd1>;
qcom,rproc_rpd = <&q6v5_wcss>;
qcom,multipd_arch;
qcom,userpd-subsys-name = "q6v5_wcss_userpd1";
memory-region = <&q6_region>;
qcom,wsi = <&wsi>;
qcom,wsi_index = <0>;
qcom,board_id = <0x12>;
status = "okay";
};
&qcn9224_pcie1 {
status = "okay";
};
&blsp1_uart0 {
pinctrl-0 = <&serial_0_pins>;
pinctrl-names = "default";
status = "okay";
};
&blsp1_uart1 {
pinctrl-0 = <&serial_1_pins &pta_slic>;
pinctrl-names = "default";
status = "okay";
};
&blsp1_i2c1 {
status = "okay";
clock-frequency = <400000>;
pinctrl-0 = <&i2c_1_pins>;
pinctrl-names = "default";
extgpio:pca9555@20{
compatible = "nxp,pca9555";
reg = <0x20>;
pinctrl-names = "default";
gpio-controller;
#gpio-cells = <2>;
status = "okay";
};
extgpio2:pca9555@21{
compatible = "nxp,pca9555";
reg = <0x21>;
pinctrl-names = "default";
gpio-controller;
#gpio-cells = <2>;
status = "okay";
};
lsm303_acc@19{
compatible = "st,lsm303agr_acc";
reg = <0x19>;
};
lsm303_mag@1e{
compatible = "st,lsm303agr_mag";
reg = <0x1e>;
};
ilps22qs@5c{
compatible = "st,ilps22qs";
reg = <0x5c>;
};
temp-sense@70 {
compatible = "ti,tmp103";
reg = <0x70>;
};
};
&blsp1_spi0 {
pinctrl-0 = <&spi_0_data_clk_pins &spi_0_cs_pins>;
pinctrl-names = "default";
status = "okay";
flash@0 {
compatible = "n25q128a11", "micron,n25q128a11", "jedec,spi-nor";
reg = <0>;
#address-cells = <1>;
#size-cells = <1>;
spi-max-frequency = <50000000>;
};
};
&blsp1_spi2 {
pinctrl-0 = <&spi_2_pins>;
pinctrl-names = "default";
cs-select = <0>;
status = "disabled";
};
&sdhc {
bus-width = <4>;
max-frequency = <192000000>;
mmc-ddr-1_8v;
mmc-hs200-1_8v;
non-removable;
pinctrl-0 = <&sdc_default_state>;
reset = <&tlmm 20 0>;
pinctrl-names = "default";
status = "okay";
};
&sleep_clk {
clock-frequency = <32000>;
};
&xo {
clock-frequency = <24000000>;
};
&qpic_bam {
status = "okay";
};
&pcie1_phy_x2 {
status = "okay";
};
&pcie0_phy {
status = "okay";
};
&pcie0 {
pinctrl-0 = <&pcie0_default_state>;
pinctrl-names = "default";
perst-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>;
status = "okay";
};
&pcie1 {
pinctrl-0 = <&pcie1_default_state>;
pinctrl-names = "default";
perst-gpios = <&tlmm 47 GPIO_ACTIVE_LOW>;
status = "okay";
pcie1_rp {
reg = <0 0 0 0 0>;
qcom,mhi@1 {
reg = <0 0 0 0 0>;
boot-args = <0x2 0x4 0x34 0x3 0x0 0x0 /* MX Rail, GPIO52, Drive strength 0x3 */
0x4 0x4 0x18 0x3 0x0 0x0 /* RFA1p2 Rail, GPIO24, Drive strength 0x3 */
0x0 0x4 0x0 0x0 0x0 0x0>; /* End of arguments */
memory-region = <&qcn9224_pcie1>;
qcom,wsi = <&wsi>;
qcom,wsi_index = <1>;
qcom,board_id = <0x1015>;
};
};
};
/* PINCTRL */
&tlmm {
i2c_1_pins: i2c-1-state {
pins = "gpio29", "gpio30";
function = "blsp1_i2c0";
drive-strength = <8>;
bias-pull-up;
};
spi_2_pins: spi-2-pins {
pins = "gpio33", "gpio34", "gpio35", "gpio36";
function = "blsp2_spi0";
drive-strength = <8>;
bias-pull-down;
};
pta_slic: pta_slic {
pta1_0 {
pins = "gpio49";
function = "pta1_0";
drive-strength = <8>;
bias-disable;
};
pta1_1 {
pins = "gpio50";
function = "pta1_1";
drive-strength = <8>;
bias-disable;
};
pta1_2 {
pins = "gpio51";
function = "pta1_2";
drive-strength = <8>;
bias-disable;
};
};
spi_0_data_clk_pins: spi-0-data-clk-state {
pins = "gpio14", "gpio15", "gpio16";
function = "blsp0_spi";
drive-strength = <2>;
bias-pull-down;
};
spi_0_cs_pins: spi-0-cs-state {
pins = "gpio17";
function = "blsp0_spi";
drive-strength = <2>;
bias-pull-up;
};
serial_1_pins: serial1-pinmux {
pins = "gpio33", "gpio34", "gpio35", "gpio36";
function = "blsp1_uart2";
drive-strength = <8>;
bias-pull-up;
};
button_pins: button-state {
pins = "gpio24";
function = "gpio";
drive-strength = <8>;
bias-pull-up;
};
pwm_pins: pwm-state {
mux_1 {
pins = "gpio25";
function = "pwm2";
drive-strength = <8>;
};
mux_2 {
pins = "gpio26";
function = "pwm2";
drive-strength = <8>;
};
mux_3 {
pins = "gpio31";
function = "pwm1";
drive-strength = <8>;
};
};
sdc_default_state: sdc-default-state {
clk-pins {
pins = "gpio13";
function = "sdc_clk";
drive-strength = <8>;
bias-disable;
};
cmd-pins {
pins = "gpio12";
function = "sdc_cmd";
drive-strength = <8>;
bias-pull-up;
};
data-pins {
pins = "gpio8", "gpio9", "gpio10", "gpio11";
function = "sdc_data";
drive-strength = <8>;
bias-pull-up;
};
};
pcie0_default_state: pcie0-default-state {
pins = "gpio38";
function = "gpio";
drive-strength = <8>;
bias-pull-up;
output-low;
};
pcie1_default_state: pcie1-default-state {
pins = "gpio47";
function = "gpio";
drive-strength = <8>;
bias-pull-up;
output-low;
};
};
&license_manager {
status = "okay";
};
&usb3 {
qcom,select-utmi-as-pipe-clk;
status = "okay";
dwc3@8a00000 {
/delete-property/ #phy-cells;
/delete-property/ phys;
/delete-property/ phy-names;
};
};
&pwm {
pinctrl-0 = <&pwm_pins>;
pinctrl-names = "default";
dft-pwm-status = <0>, <0>, <1>, <0>;
poe_type_pin = <&extgpio 0 0 &extgpio 1 0 &extgpio 2 0>;
status = "okay";
};
&hs_m31phy_0 {
status = "okay";
};

View File

@@ -15,7 +15,7 @@
#include "ipq5332-default-memory.dtsi" #include "ipq5332-default-memory.dtsi"
/ { / {
model = "Sercomm WiFi-7"; model = "Sercomm AP72TIP-v4";
compatible = "sercomm,ap72tip-v4", "qcom,ipq5332-ap-mi01.6", "qcom,ipq5332"; compatible = "sercomm,ap72tip-v4", "qcom,ipq5332-ap-mi01.6", "qcom,ipq5332";
aliases { aliases {

View File

@@ -15,7 +15,7 @@
#include "ipq5332-default-memory.dtsi" #include "ipq5332-default-memory.dtsi"
/ { / {
model = "Sercomm WiFi-7"; model = "Sercomm AP72TIP";
compatible = "sercomm,ap72tip", "qcom,ipq5332-ap-mi01.6", "qcom,ipq5332"; compatible = "sercomm,ap72tip", "qcom,ipq5332-ap-mi01.6", "qcom,ipq5332";
aliases { aliases {
@@ -255,7 +255,7 @@
gpios = <&tca6416 14 GPIO_ACTIVE_HIGH>; gpios = <&tca6416 14 GPIO_ACTIVE_HIGH>;
}; };
}; };
/*
gpio_keys { gpio_keys {
compatible = "gpio-keys"; compatible = "gpio-keys";
pinctrl-0 = <&button_pins>; pinctrl-0 = <&button_pins>;
@@ -263,11 +263,11 @@
button@1 { button@1 {
label = "rst"; label = "rst";
linux,code = <KEY_RESTART>; linux,code = <KEY_RESTART>;
gpios = <&tlmm 25 GPIO_ACTIVE_LOW>; gpios = <&tlmm 1 GPIO_ACTIVE_LOW>;
linux,input-type = <1>; linux,input-type = <1>;
debounce-interval = <60>; debounce-interval = <60>;
}; };
};*/ };
wsi: wsi { wsi: wsi {
id = <0>; id = <0>;
@@ -546,13 +546,13 @@
drive-strength = <8>; drive-strength = <8>;
bias-pull-down; bias-pull-down;
};*/ };*/
/*
button_pins: button-state { button_pins: button-state {
pins = "gpio25"; pins = "gpio1";
function = "gpio"; function = "gpio";
drive-strength = <8>; drive-strength = <8>;
bias-pull-up; bias-pull-up;
};*/ };
pwm_pins: pwm-state { pwm_pins: pwm-state {
pins = "gpio46"; pins = "gpio46";

View File

@@ -0,0 +1,687 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
* IPQ5332 RDP477 board device tree source
*
* Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
/dts-v1/;
#include "ipq5332.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/leds/common.h>
#include "ipq5332-default-memory.dtsi"
/ {
model = "SONICFI RAP750E-S";
compatible = "sonicfi,rap750e-s","qcom,ipq5332-ap-mi01.3-c2", "qcom,ipq5332";
#ifdef __IPQ_MEM_PROFILE_512_MB__
/* 512M Memory Layout for IPQ5332 + QCN6432
* +==========+==============+========================+
* | | | |
* | Region | Start Offset | Size |
* | | | |
* +---------+--------------+-------------------------+
* | Q6 | | |
* | code/ | 0x4A900000 | 20MB |
* | data | | |
* +---------+--------------+-------------------------+
* | IPQ5332 | | |
* | data | 0x4BD00000 | 17MB |
* +---------+--------------+-------------------------+
* | IPQ5332 | | |
* | M3 Dump | 0x4CE00000 | 1MB |
* +---------+--------------+-------------------------+
* | IPQ5332 | | |
* | QDSS | 0x4CF00000 | 1MB |
* +---------+--------------+-------------------------+
* |IPQ5332 | | |
* | CALDB | 0x4D000000 | 3MB |
* +---------+--------------+-------------------------+
* |QCN6432_1| | |
* | data | 0x4D300000 | 16MB |
* +---------+--------------+-------------------------+
* |QCN6432_1| | |
* | M3 Dump | 0x4E300000 | 1MB |
* +---------+--------------+-------------------------+
* |QCN6432_1| | |
* | QDSS | 0x4E400000 | 1MB |
* +---------+--------------+-------------------------+
* |QCN6432_1| | |
* | CALDB | 0x4E500000 | 5MB |
* +---------+--------------+-------------------------+
* |QCN6432_1| | |
* |MEM_HOLE | 0x4EA00000 | 5MB |
* +---------+--------------+-------------------------+
* | | | |
* | MLO | 0x4EF00000 | 17MB |
* +==================================================+
* | |
* | |
* | |
* | Rest of memory for Linux |
* | |
* | |
* | |
* +==================================================+
*/
reserved-memory {
/delete-node/ m3_dump@4cc00000;
/delete-node/ q6_etr_dump@1;
/delete-node/ mlo_global_mem_0@0x4db00000;
/delete-node/ wcnss@4a900000;
/delete-node/ q6_caldb_region@4ce00000;
q6_mem_regions: q6_mem_regions@4A900000 {
no-map;
reg = <0x0 0x4A900000 0x0 0x4600000>;
};
q6_code_data: q6_code_data@4A900000 {
no-map;
reg = <0x0 0x4A900000 0x0 0x1400000>;
};
q6_ipq5332_data: q6_ipq5332_data@4BD00000 {
no-map;
reg = <0x0 0x4BD00000 0x0 0x1100000>;
};
m3_dump: m3_dump@4CE00000 {
no-map;
reg = <0x0 0x4CE00000 0x0 0x100000>;
};
q6_etr_region: q6_etr_dump@4CF00000 {
no-map;
reg = <0x0 0x4CF00000 0x0 0x100000>;
};
q6_ipq5332_caldb: q6_ipq5332_caldb@4D000000 {
no-map;
reg = <0x0 0x4D000000 0x0 0x300000>;
};
q6_qcn6432_data_1: q6_qcn6432_data_1@4D300000 {
no-map;
reg = <0x0 0x4D300000 0x0 0x1000000>;
};
m3_dump_qcn6432_1: m3_dump_qcn6432_1@4E300000 {
no-map;
reg = <0x0 0x4E300000 0x0 0x100000>;
};
q6_qcn6432_etr_1: q6_qcn6432_etr_1@4E400000 {
no-map;
reg = <0x0 0x4E400000 0x0 0x100000>;
};
q6_qcn6432_caldb_1: q6_qcn6432_caldb_1@4E500000 {
no-map;
reg = <0x0 0x4E500000 0x0 0x500000>;
};
mlo_global_mem0: mlo_global_mem_0@4EF00000 {
no-map;
reg = <0x0 0x4EF00000 0x0 0x1100000>;
};
};
#else
/* 1G Memory Layout for IPQ5332 + QCN6432
* +==========+==============+========================+
* | | | |
* | Region | Start Offset | Size |
* | | | |
* +---------+--------------+-------------------------+
* | Q6 | | |
* | code/ | 0x4A900000 | 20MB |
* | data | | |
* +---------+--------------+-------------------------+
* | IPQ5332 | | |
* | data | 0x4BD00000 | 21MB |
* +---------+--------------+-------------------------+
* | IPQ5332 | | |
* | M3 Dump | 0x4D200000 | 1MB |
* +---------+--------------+-------------------------+
* | IPQ5332 | | |
* | QDSS | 0x4D300000 | 1MB |
* +---------+--------------+-------------------------+
* |IPQ5332 | | |
* | CALDB | 0x4D400000 | 5MB |
* +---------+--------------+-------------------------+
* |QCN6432_1| | |
* | data | 0x4D900000 | 21MB |
* +---------+--------------+-------------------------+
* |QCN6432_1| | |
* | M3 Dump | 0x4EE00000 | 1MB |
* +---------+--------------+-------------------------+
* |QCN6432_1| | |
* | QDSS | 0x4EF00000 | 1MB |
* +---------+--------------+-------------------------+
* |QCN6432_1| | |
* | CALDB | 0x4F000000 | 5MB |
* +---------+--------------+-------------------------+
* |QCN6432_1| | |
* |MEM_HOLE | 0x4F500000 | 5MB |
* +---------+--------------+-------------------------+
* | | | |
* | MLO | 0x4FA00000 | 17MB |
* +==================================================+
* | |
* | |
* | |
* | Rest of memory for Linux |
* | |
* | |
* | |
* +==================================================+
*/
reserved-memory {
/delete-node/ m3_dump@4cc00000;
/delete-node/ q6_etr_dump@1;
/delete-node/ mlo_global_mem_0@0x4db00000;
/delete-node/ wcnss@4a900000;
/delete-node/ q6_caldb_region@4ce00000;
q6_mem_regions: q6_mem_regions@4A900000 {
no-map;
reg = <0x0 0x4A900000 0x0 0x5100000>;
};
q6_code_data: q6_code_data@4A900000 {
no-map;
reg = <0x0 0x4A900000 0x0 0x1400000>;
};
q6_ipq5332_data: q6_ipq5332_data@4BD00000 {
no-map;
reg = <0x0 0x4BD00000 0x0 0x1500000>;
};
m3_dump: m3_dump@4D200000 {
no-map;
reg = <0x0 0x4D200000 0x0 0x100000>;
};
q6_etr_region: q6_etr_dump@4D300000 {
no-map;
reg = <0x0 0x4D300000 0x0 0x100000>;
};
q6_ipq5332_caldb: q6_ipq5332_caldb@4D400000 {
no-map;
reg = <0x0 0x4D400000 0x0 0x500000>;
};
q6_qcn6432_data_1: q6_qcn6432_data_1@4D900000 {
no-map;
reg = <0x0 0x4D900000 0x0 0x1500000>;
};
m3_dump_qcn6432_1: m3_dump_qcn6432_1@4EE00000 {
no-map;
reg = <0x0 0x4EE00000 0x0 0x100000>;
};
q6_qcn6432_etr_1: q6_qcn6432_etr_1@4EF00000 {
no-map;
reg = <0x0 0x4EF00000 0x0 0x100000>;
};
q6_qcn6432_caldb_1: q6_qcn6432_caldb_1@4F000000 {
no-map;
reg = <0x0 0x4F000000 0x0 0x500000>;
};
mlo_global_mem0: mlo_global_mem_0@4FA00000 {
no-map;
reg = <0x0 0x4FA00000 0x0 0x1100000>;
};
};
#endif
aliases {
serial0 = &blsp1_uart0;
serial1 = &blsp1_uart1;
ethernet0 = "/soc/dp1";
//ethernet1 = "/soc/dp2";
led-boot = &led_power;
led-failsafe = &led_power;
led-running = &led_power;
led-upgrade = &led_power;
};
chosen {
stdout-path = "serial0";
};
soc@0 {
mdio:mdio@90000 {
pinctrl-0 = <&mdio1_pins>;
pinctrl-names = "default";
/*gpio26 for manhattan reset*/
phy-reset-gpio = <&tlmm 26 GPIO_ACTIVE_LOW>;
status = "okay";
phy0: ethernet-phy@0 {
reg = <16>;
};
};
gpio_keys {
compatible = "gpio-keys";
pinctrl-0 = <&button_pins>;
pinctrl-names = "default";
status = "okay";
button@1 {
label = "reset";
linux,code = <KEY_RESTART>;
gpios = <&tlmm 24 GPIO_ACTIVE_LOW>;
linux,input-type = <1>;
debounce-interval = <60>;
};
};
pwmleds {
compatible = "pwm-leds";
red {
label = "pwm:red";
pwms = <&pwm 2 1250000>;
max-brightness = <255>;
linux,default-trigger = "none";
};
green {
label = "pwm:green";
pwms = <&pwm 3 1250000>;
max-brightness = <255>;
linux,default-trigger = "none";
};
led_power: blue {
label = "pwm:blue";
pwms = <&pwm 1 1250000>;
max-brightness = <255>;
linux,default-trigger = "none";
};
white {
label = "pwm:white";
pwms = <&pwm 0 1250000>;
max-brightness = <255>;
linux,default-trigger = "none";
};
};
ess-instance {
num_devices = <0x1>;
ess-switch@3a000000 {
switch_cpu_bmp = <0x1>; /* cpu port bitmap */
switch_lan_bmp = <0x4>; /* lan port bitmap */
switch_wan_bmp = <0x0>; /* wan port bitmap */
switch_mac_mode = <0xff>; /* mac mode for uniphy instance0*/
switch_mac_mode1 = <0xf>; /* mac mode for uniphy instance1*/
switch_mac_mode2 = <0xff>; /* mac mode for uniphy instance2*/
qcom,port_phyinfo {
port@1 {
port_id = <2>;
phy_address = <16>;
};
};
};
};
dp1 {
device_type = "network";
compatible = "qcom,nss-dp";
qcom,id = <2>;
reg = <0x3a504000 0x4000>;
qcom,mactype = <1>;
local-mac-address = [000000000000];
mdio-bus = <&mdio>;
qcom,phy-mdio-addr = <16>;
qcom,link-poll = <1>;
phy-mode = "sgmii";
};
/* EDMA host driver configuration for the board */
edma@3ab00000 {
qcom,txdesc-ring-start = <4>; /* Tx desc ring start ID */
qcom,txdesc-rings = <12>; /* Total number of Tx desc rings to be provisioned */
qcom,mht-txdesc-rings = <8>; /* Extra Tx desc rings to be provisioned for MHT SW ports */
qcom,txcmpl-ring-start = <4>; /* Tx complete ring start ID */
qcom,txcmpl-rings = <12>; /* Total number of Tx complete rings to be provisioned */
qcom,mht-txcmpl-rings = <8>; /* Extra Tx complete rings to be provisioned for mht sw ports. */
qcom,rxfill-ring-start = <4>; /* Rx fill ring start ID */
qcom,rxfill-rings = <4>; /* Total number of Rx fill rings to be provisioned */
qcom,rxdesc-ring-start = <12>; /* Rx desc ring start ID */
qcom,rxdesc-rings = <4>; /* Total number of Rx desc rings to be provisioned */
qcom,rx-page-mode = <0>; /* Rx fill ring page mode */
qcom,tx-map-priority-level = <1>; /* Tx priority level per port */
qcom,rx-map-priority-level = <1>; /* Rx priority level per core */
qcom,ppeds-num = <2>; /* Number of PPEDS nodes */
/* PPE-DS node format: <Rx-fill Tx-cmpl Rx Tx Queue-base Queue-count> */
qcom,ppeds-map = <1 1 1 1 32 8>, /* PPEDS Node#0 ring and queue map */
<2 2 2 2 40 8>; /* PPEDS Node#1 ring and queue map */
qcom,txdesc-map = <8 9 10 11>, /* Port0 per-core Tx ring map */
<12 13 14 15>, /* MHT-Port1 per-core Tx ring map */
<4 5 6 7>, /* MHT-Port2 per-core Tx ring map/packets from vp*/
<16 17 18 19>, /* MHT-Port3 per-core Tx ring map */
<20 21 22 23>; /* MHT-Port4 per-core Tx ring map */
qcom,txdesc-fc-grp-map = <1 2 3 4 5>; /* Per GMAC flow control group map */
qcom,rxfill-map = <4 5 6 7>; /* Per-core Rx fill ring map */
qcom,rxdesc-map = <12 13 14 15>; /* Per-core Rx desc ring map */
qcom,rx-queue-start = <0>; /* Rx queue start */
qcom,rx-ring-queue-map = <0 8 16 24>, /* Priority 0 queues per-core Rx ring map */
<1 9 17 25>, /* Priority 1 queues per-core Rx ring map */
<2 10 18 26>, /* Priority 2 queues per-core Rx ring map */
<3 11 19 27>, /* Priority 3 queues per-core Rx ring map */
<4 12 20 28>, /* Priority 4 queues per-core Rx ring map */
<5 13 21 29>, /* Priority 5 queues per-core Rx ring map */
<6 14 22 30>, /* Priority 6 queues per-core Rx ring map */
<7 15 23 31>; /* Priority 7 queues per-core Rx ring map */
interrupts = <0 163 4>, /* Tx complete ring id #4 IRQ info */
<0 164 4>, /* Tx complete ring id #5 IRQ info */
<0 165 4>, /* Tx complete ring id #6 IRQ info */
<0 166 4>, /* Tx complete ring id #7 IRQ info */
<0 167 4>, /* Tx complete ring id #8 IRQ info */
<0 168 4>, /* Tx complete ring id #9 IRQ info */
<0 169 4>, /* Tx complete ring id #10 IRQ info */
<0 170 4>, /* Tx complete ring id #11 IRQ info */
<0 171 4>, /* Tx complete ring id #12 IRQ info */
<0 172 4>, /* Tx complete ring id #13 IRQ info */
<0 173 4>, /* Tx complete ring id #14 IRQ info */
<0 174 4>, /* Tx complete ring id #15 IRQ info */
<0 139 4>, /* Rx desc ring id #12 IRQ info */
<0 140 4>, /* Rx desc ring id #13 IRQ info */
<0 141 4>, /* Rx desc ring id #14 IRQ info */
<0 142 4>, /* Rx desc ring id #15 IRQ info */
<0 191 4>, /* Misc error IRQ info */
<0 160 4>, /* PPEDS Node #1(TxComp ring id #1) TxComplete IRQ info */
<0 128 4>, /* PPEDS Node #1(Rx Desc ring id #1) Rx Desc IRQ info */
<0 152 4>, /* PPEDS Node #1(RxFill Desc ring id #1) Rx Fill IRQ info */
<0 161 4>, /* PPEDS Node #2(TxComp ring id #2) TxComplete IRQ info */
<0 129 4>, /* PPEDS Node #2(Rx Desc ring id #2) Rx Desc IRQ info */
<0 153 4>, /* PPEDS Node #2(RxFill Desc ring id #2) Rx Fill IRQ info */
<0 175 4>, /* MHT port Tx complete ring id #16 IRQ info */
<0 176 4>, /* MHT port Tx complete ring id #17 IRQ info */
<0 177 4>, /* MHT port Tx complete ring id #18 IRQ info */
<0 178 4>, /* MHT port Tx complete ring id #19 IRQ info */
<0 179 4>, /* MHT port Tx complete ring id #20 IRQ info */
<0 180 4>, /* MHT port Tx complete ring id #21 IRQ info */
<0 181 4>, /* MHT port Tx complete ring id #22 IRQ info */
<0 182 4>; /* MHT port Tx complete ring id #23 IRQ info */
};
wsi: wsi {
id = <0>;
num_chip = <2>;
status = "okay";
chip_info = <0 1 1>,
<1 1 0>;
};
q6v5_wcss: remoteproc@d100000 {
boot-args = <0x1 0x4 0x3 0x0 0x26 0x2>;
memory-region = <&q6_mem_regions>;
q6_wcss_pd1: remoteproc_pd1 {
status = "okay";
};
q6_wcss_pd2: remoteproc_pd2 {
compatible = "qcom,ipq5332-wcss-pcie-mpd";
firmware = "IPQ5332/q6_fw2.mdt";
m3_firmware = "qcn6432/iu_fw.mdt";
interrupts-extended = <&wcss_smp2p_in 16 0>,
<&wcss_smp2p_in 17 0>,
<&wcss_smp2p_in 20 0>,
<&wcss_smp2p_in 19 0>;
interrupt-names = "fatal",
"ready",
"spawn-ack",
"stop-ack";
qcom,smem-states = <&wcss_smp2p_out 16>,
<&wcss_smp2p_out 17>,
<&wcss_smp2p_out 18>;
qcom,smem-state-names = "shutdown",
"stop",
"spawn";
status = "okay";
};
};
};
};
&blsp1_uart0 {
pinctrl-0 = <&serial_0_pins>;
pinctrl-names = "default";
status = "okay";
};
/*
&blsp1_uart1 {
pinctrl-0 = <&serial_1_pins>;
pinctrl-names = "default";
status = "disabled";
};
*/
&blsp1_i2c1 {
clock-frequency = <400000>;
pinctrl-0 = <&i2c_1_pins>;
pinctrl-names = "default";
status = "okay";
};
&blsp1_spi0 {
status = "disabled";
};
&sdhc {
bus-width = <4>;
max-frequency = <192000000>;
mmc-ddr-1_8v;
mmc-hs200-1_8v;
non-removable;
pinctrl-0 = <&sdc_default_state>;
pinctrl-names = "default";
status = "disabled";
};
&sleep_clk {
clock-frequency = <32000>;
};
&xo {
clock-frequency = <24000000>;
};
&qpic_bam {
status = "okay";
};
&qpic_nand {
pinctrl-0 = <&qspi_default_state>;
pinctrl-names = "default";
status = "okay";
nandcs@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <1>;
nand-ecc-strength = <8>;
nand-ecc-step-size = <512>;
nand-bus-width = <8>;
};
};
/* PINCTRL */
&tlmm {
qspi_default_state: qspi-default-state {
qspi_clock {
pins = "gpio13";
function = "qspi_clk";
drive-strength = <8>;
bias-pull-down;
};
qspi_cs {
pins = "gpio12";
function = "qspi_cs";
drive-strength = <8>;
bias-pull-up;
};
qspi_data {
pins = "gpio8", "gpio9", "gpio10", "gpio11";
function = "qspi_data";
drive-strength = <8>;
bias-pull-down;
};
};
pwm_pins: pwm_pinmux {
/* PWM LED GREEN */
mux_1 {
pins = "gpio43";
function = "pwm0";
drive-strength = <8>;
};
/* PWM LED BLUE */
mux_2 {
pins = "gpio45";
function = "pwm0";
drive-strength = <8>;
};
/* PWM LED RED */
mux_3 {
pins = "gpio44";
function = "pwm0";
drive-strength = <8>;
};
/* PWM LED WHITE */
mux_4 {
pins = "gpio46";
function = "pwm0";
drive-strength = <8>;
};
};
/*
serial_1_pins: serial1-pinmux {
pins = "gpio33", "gpio34", "gpio35", "gpio36";
function = "blsp1_uart2";
drive-strength = <8>;
bias-pull-up;
};
*/
i2c_1_pins: i2c-1-state {
pins = "gpio29", "gpio30";
function = "blsp1_i2c0";
drive-strength = <8>;
bias-pull-up;
};
/*
gpio_leds_default: gpio-leds-default-state {
pins = "gpio36";
function = "gpio";
drive-strength = <8>;
bias-pull-down;
};
*/
button_pins: button-state {
pins = "gpio24";
function = "gpio";
drive-strength = <8>;
bias-pull-up;
};
sdc_default_state: sdc-default-state {
clk-pins {
pins = "gpio13";
function = "sdc_clk";
drive-strength = <8>;
bias-disable;
};
cmd-pins {
pins = "gpio12";
function = "sdc_cmd";
drive-strength = <8>;
bias-pull-up;
};
data-pins {
pins = "gpio8", "gpio9", "gpio10", "gpio11";
function = "sdc_data";
drive-strength = <8>;
bias-pull-up;
};
};
};
&license_manager {
status = "okay";
};
&usb3 {
qcom,select-utmi-as-pipe-clk;
status = "disabled";
};
&pwm {
pinctrl-0 = <&pwm_pins>;
used-pwm-indices = <1>, <1>, <1>, <1>;
pinctrl-names = "default";
status = "okay";
};
&hs_m31phy_0 {
status = "okay";
};
&wifi0 {
qcom,multipd_arch;
qcom,rproc = <&q6_wcss_pd1>;
qcom,rproc_rpd = <&q6v5_wcss>;
qcom,userpd-subsys-name = "q6v5_wcss_userpd1";
qcom,bdf-addr = <0x4BD00000 0x4BD00000 0x0 0x0 0x0 0x0>;
qcom,caldb-addr = <0x4D400000 0x4D000000 0x0 0x0 0x0 0x0>;
#ifdef __IPQ_MEM_PROFILE_512_MB__
qcom,tgt-mem-mode = <1>;
qcom,caldb-size = <0x300000>;
#else
qcom,tgt-mem-mode = <0>;
qcom,caldb-size = <0x500000>;
#endif
qcom,board_id = <0x1b>;
memory-region = <&q6_ipq5332_data>;
qcom,wsi = <&wsi>;
qcom,wsi_index = <0>;
status = "okay";
};
&wifi1 {
qcom,multipd_arch;
qcom,rproc = <&q6_wcss_pd2>;
qcom,rproc_rpd = <&q6v5_wcss>;
qcom,userpd-subsys-name = "q6v5_wcss_userpd2";
qcom,bdf-addr = <0x4D900000 0x4D300000 0x0 0x0 0x0 0x0>;
qcom,caldb-addr = <0x4F000000 0x4E500000 0x0 0x0 0x0 0x0>;
qcom,umac-irq-reset-addr = <0x20000884>;
qcom,caldb-size = <0x500000>;
#ifdef __IPQ_MEM_PROFILE_512_MB__
qcom,tgt-mem-mode = <1>;
#else
qcom,tgt-mem-mode = <0>;
#endif
qcom,board_id = <0x060>;
memory-region = <&q6_qcn6432_data_1>;
qcom,wsi = <&wsi>;
qcom,wsi_index = <1>;
status = "okay";
interrupts = <GIC_SPI 33 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "umac_reset";
};

View File

@@ -0,0 +1,157 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* STMicroelectronics ilps22qs driver
*
* Copyright 2023 STMicroelectronics Inc.
*
* MEMS Software Solutions Team
*/
#ifndef __ST_ILPS22QS_H
#define __ST_ILPS22QS_H
#include <linux/bitfield.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#define ST_ILPS22QS_DEV_NAME "ilps22qs"
#define ST_ILPS28QSW_DEV_NAME "ilps28qsw"
#define ST_ILPS22QS_WHO_AM_I_ADDR 0x0f
#define ST_ILPS22QS_WHOAMI_VAL 0xb4
#define ST_ILPS22QS_CTRL1_ADDR 0x10
#define ST_ILPS22QS_ODR_MASK GENMASK(6, 3)
#define ST_ILPS22QS_CTRL2_ADDR 0x11
#define ST_ILPS22QS_SOFT_RESET_MASK BIT(2)
#define ST_ILPS22QS_BDU_MASK BIT(3)
#define ST_ILPS22QS_CTRL3_ADDR 0x12
#define ST_ILPS22QS_AH_QVAR_EN_MASK BIT(7)
#define ST_ILPS22QS_AH_QVAR_P_AUTO_EN_MASK BIT(5)
#define ST_ILPS22QS_PRESS_OUT_XL_ADDR 0x28
#define ST_ILPS22QS_TEMP_OUT_L_ADDR 0x2b
#define ST_ILPS22QS_PRESS_FS_AVL_GAIN (1000000000UL / 4096UL)
#define ST_ILPS22QS_TEMP_FS_AVL_GAIN 100
#define ST_ILPS22QS_QVAR_FS_AVL_GAIN 438000
#define ST_ILPS22QS_SHIFT_VAL(val, mask) (((val) << __ffs(mask)) & (mask))
#define ST_ILPS22QS_ODR_LIST_NUM 8
enum st_ilps22qs_sensor_id {
ST_ILPS22QS_PRESS = 0,
ST_ILPS22QS_TEMP,
ST_ILPS22QS_QVAR,
ST_ILPS22QS_SENSORS_NUM,
};
struct st_ilps22qs_odr_t {
u8 hz;
u8 val;
};
struct st_ilps22qs_reg {
u8 addr;
u8 mask;
};
struct st_ilps22qs_odr_table_t {
u8 size;
struct st_ilps22qs_reg reg;
struct st_ilps22qs_odr_t odr_avl[ST_ILPS22QS_ODR_LIST_NUM];
};
struct st_ilps22qs_hw {
struct iio_dev *iio_devs[ST_ILPS22QS_SENSORS_NUM];
struct workqueue_struct *workqueue;
struct regulator *vddio_supply;
struct regulator *vdd_supply;
struct regmap *regmap;
struct device *dev;
struct mutex lock;
bool interleave;
u8 enable_mask;
u8 odr;
};
struct st_ilps22qs_sensor {
enum st_ilps22qs_sensor_id id;
struct work_struct iio_work;
struct st_ilps22qs_hw *hw;
struct hrtimer hr_timer;
ktime_t ktime;
int64_t timestamp;
char name[32];
u32 gain;
u8 odr;
};
extern const struct dev_pm_ops st_ilps22qs_pm_ops;
static inline int st_ilps22qs_update_locked(struct st_ilps22qs_hw *hw,
unsigned int addr,
unsigned int mask,
unsigned int data)
{
unsigned int val = ST_ILPS22QS_SHIFT_VAL(data, mask);
int err;
mutex_lock(&hw->lock);
err = regmap_update_bits(hw->regmap, addr, mask, val);
mutex_unlock(&hw->lock);
return err;
}
static inline int st_ilps22qs_read_locked(struct st_ilps22qs_hw *hw,
unsigned int addr, void *val,
unsigned int len)
{
int err;
mutex_lock(&hw->lock);
err = regmap_bulk_read(hw->regmap, addr, val, len);
mutex_unlock(&hw->lock);
return err;
}
static inline void st_ilps22qs_flush_works(struct st_ilps22qs_hw *hw)
{
flush_workqueue(hw->workqueue);
}
static inline int st_ilps22qs_destroy_workqueue(struct st_ilps22qs_hw *hw)
{
if (hw->workqueue)
destroy_workqueue(hw->workqueue);
return 0;
}
static inline int st_ilps22qs_allocate_workqueue(struct st_ilps22qs_hw *hw)
{
if (!hw->workqueue)
hw->workqueue = create_workqueue(ST_ILPS22QS_DEV_NAME);
return !hw->workqueue ? -ENOMEM : 0;
}
static inline s64 st_ilps22qs_get_time_ns(struct st_ilps22qs_hw *hw)
{
return iio_get_time_ns(hw->iio_devs[ST_ILPS22QS_PRESS]);
}
int st_ilps22qs_probe(struct device *dev, struct regmap *regmap);
int st_ilps22qs_remove(struct device *dev);
#endif /* __ST_ILPS22QS_H */

View File

@@ -0,0 +1,927 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* STMicroelectronics ilps22qs driver
*
* Copyright 2023 STMicroelectronics Inc.
*
* MEMS Software Solutions Team
*/
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/iio/buffer.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/version.h>
#if KERNEL_VERSION(6, 11, 0) < LINUX_VERSION_CODE
#include <linux/unaligned.h>
#else /* LINUX_VERSION_CODE */
#include <asm/unaligned.h>
#endif /* LINUX_VERSION_CODE */
#include "st_ilps22qs.h"
static const struct st_ilps22qs_odr_table_t st_ilps22qs_odr_table = {
.size = ST_ILPS22QS_ODR_LIST_NUM,
.reg = {
.addr = ST_ILPS22QS_CTRL1_ADDR,
.mask = ST_ILPS22QS_ODR_MASK,
},
.odr_avl[0] = { 1, 0x01 },
.odr_avl[1] = { 4, 0x02 },
.odr_avl[2] = { 10, 0x03 },
.odr_avl[3] = { 25, 0x04 },
.odr_avl[4] = { 50, 0x05 },
.odr_avl[5] = { 75, 0x06 },
.odr_avl[6] = { 100, 0x07 },
.odr_avl[7] = { 200, 0x08 },
};
static const struct iio_chan_spec st_ilps22qs_press_channels[] = {
{
.type = IIO_PRESSURE,
.address = ST_ILPS22QS_PRESS_OUT_XL_ADDR,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.channel2 = IIO_NO_MOD,
.scan_index = 0,
.scan_type = {
.sign = 'u',
.realbits = 24,
.storagebits = 32,
.endianness = IIO_LE,
},
},
IIO_CHAN_SOFT_TIMESTAMP(1)
};
static const struct iio_chan_spec st_ilps22qs_temp_channels[] = {
{
.type = IIO_TEMP,
.address = ST_ILPS22QS_TEMP_OUT_L_ADDR,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.channel2 = IIO_NO_MOD,
.scan_index = 0,
.scan_type = {
.sign = 's',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_LE,
},
},
IIO_CHAN_SOFT_TIMESTAMP(1)
};
static const struct iio_chan_spec st_ilps22qs_qvar_channels[] = {
{
.type = IIO_ALTVOLTAGE,
.address = ST_ILPS22QS_PRESS_OUT_XL_ADDR,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.channel2 = IIO_NO_MOD,
.scan_index = 0,
.scan_type = {
.sign = 's',
.realbits = 24,
.storagebits = 32,
.endianness = IIO_LE,
}
},
IIO_CHAN_SOFT_TIMESTAMP(1),
};
static enum hrtimer_restart
st_ilps22qs_poll_function_read(struct hrtimer *timer)
{
struct st_ilps22qs_sensor *sensor;
sensor = container_of((struct hrtimer *)timer,
struct st_ilps22qs_sensor, hr_timer);
sensor->timestamp = st_ilps22qs_get_time_ns(sensor->hw);
queue_work(sensor->hw->workqueue, &sensor->iio_work);
return HRTIMER_NORESTART;
}
static void st_ilps22qs_report_temp(struct st_ilps22qs_sensor *sensor,
u8 *tmp, int64_t timestamp)
{
struct iio_dev *iio_dev = sensor->hw->iio_devs[sensor->id];
u8 iio_buf[ALIGN(2, sizeof(s64)) + sizeof(s64)];
memcpy(iio_buf, tmp, 2);
iio_push_to_buffers_with_timestamp(iio_dev, iio_buf, timestamp);
}
static void st_silps22qs_report_press_qvar(struct st_ilps22qs_sensor *sensor,
u8 *tmp, int64_t timestamp)
{
u8 iio_buf[ALIGN(3, sizeof(s64)) + sizeof(s64)];
struct st_ilps22qs_hw *hw = sensor->hw;
struct iio_dev *iio_dev;
mutex_lock(&hw->lock);
if (hw->interleave) {
if (tmp[0] & 0x01)
iio_dev = sensor->hw->iio_devs[ST_ILPS22QS_QVAR];
else
iio_dev = sensor->hw->iio_devs[ST_ILPS22QS_PRESS];
} else {
iio_dev = sensor->hw->iio_devs[sensor->id];
}
mutex_unlock(&hw->lock);
memcpy(iio_buf, tmp, 3);
iio_push_to_buffers_with_timestamp(iio_dev, iio_buf, timestamp);
}
static void st_ilps22qs_poll_function_work(struct work_struct *iio_work)
{
struct st_ilps22qs_sensor *sensor;
struct st_ilps22qs_hw *hw;
ktime_t tmpkt, ktdelta;
int len;
int err;
int id;
sensor = container_of((struct work_struct *)iio_work,
struct st_ilps22qs_sensor, iio_work);
hw = sensor->hw;
id = sensor->id;
/* adjust delta time */
ktdelta = ktime_set(0,
(st_ilps22qs_get_time_ns(hw) - sensor->timestamp));
/* avoid negative value in case of high odr */
mutex_lock(&hw->lock);
if (ktime_after(sensor->ktime, ktdelta))
tmpkt = ktime_sub(sensor->ktime, ktdelta);
else
tmpkt = sensor->ktime;
hrtimer_start(&sensor->hr_timer, tmpkt, HRTIMER_MODE_REL);
mutex_unlock(&sensor->hw->lock);
len = hw->iio_devs[id]->channels->scan_type.realbits >> 3;
switch (id) {
case ST_ILPS22QS_PRESS:
case ST_ILPS22QS_QVAR: {
u8 data[3];
err = st_ilps22qs_read_locked(hw,
hw->iio_devs[id]->channels->address,
data, len);
if (err < 0)
return;
st_silps22qs_report_press_qvar(sensor, data, sensor->timestamp);
}
break;
case ST_ILPS22QS_TEMP: {
u8 data[2];
err = st_ilps22qs_read_locked(hw,
hw->iio_devs[id]->channels->address,
data, len);
if (err < 0)
return;
st_ilps22qs_report_temp(sensor, data, sensor->timestamp);
}
break;
default:
break;
}
}
static int st_ilps22qs_check_whoami(struct st_ilps22qs_hw *hw)
{
int data;
int err;
err = regmap_read(hw->regmap, ST_ILPS22QS_WHO_AM_I_ADDR, &data);
if (err < 0) {
dev_err(hw->dev, "failed to read whoami register\n");
return err;
}
if (data != ST_ILPS22QS_WHOAMI_VAL) {
dev_err(hw->dev, "unsupported whoami [%02x]\n", data);
return -ENODEV;
}
return 0;
}
static __maybe_unused int st_ilps22qs_reg_access(struct iio_dev *iio_dev,
unsigned int reg,
unsigned int writeval,
unsigned int *readval)
{
struct st_ilps22qs_sensor *sensor = iio_priv(iio_dev);
int ret;
ret = iio_device_claim_direct_mode(iio_dev);
if (ret)
return ret;
if (readval == NULL)
ret = regmap_write(sensor->hw->regmap, reg, writeval);
else
ret = regmap_read(sensor->hw->regmap, reg, readval);
iio_device_release_direct_mode(iio_dev);
return (ret < 0) ? ret : 0;
}
static int st_ilps22qs_get_odr(struct st_ilps22qs_sensor *sensor, u8 odr)
{
int i;
for (i = 0; i < st_ilps22qs_odr_table.size; i++) {
if (st_ilps22qs_odr_table.odr_avl[i].hz >= odr)
break;
}
return i == st_ilps22qs_odr_table.size ? -EINVAL : i;
}
static int st_ilps22qs_set_odr(struct st_ilps22qs_sensor *sensor, u8 odr)
{
struct st_ilps22qs_hw *hw = sensor->hw;
u8 max_odr = odr;
int i;
for (i = 0; i < ST_ILPS22QS_SENSORS_NUM; i++) {
if ((hw->enable_mask & BIT(i)) && (sensor->id != i)) {
struct st_ilps22qs_sensor *temp;
temp = iio_priv(hw->iio_devs[i]);
max_odr = max_t(u32, max_odr, temp->odr);
}
}
if (max_odr != hw->odr) {
int err, ret;
ret = st_ilps22qs_get_odr(sensor, max_odr);
if (ret < 0)
return ret;
err = st_ilps22qs_update_locked(hw,
st_ilps22qs_odr_table.reg.addr,
st_ilps22qs_odr_table.reg.mask,
st_ilps22qs_odr_table.odr_avl[ret].val);
if (err < 0)
return err;
hw->odr = max_odr;
}
return 0;
}
/* need hw->lock */
static int st_ilps22qs_set_interleave(struct st_ilps22qs_sensor *sensor,
bool enable)
{
struct st_ilps22qs_hw *hw = sensor->hw;
int otherid = sensor->id == ST_ILPS22QS_PRESS ? ST_ILPS22QS_QVAR :
ST_ILPS22QS_PRESS;
int interleave;
int err = 0;
/* both press / qvar enabling ? */
mutex_lock(&hw->lock);
interleave = (!!(hw->enable_mask & BIT(otherid))) && enable;
if (interleave) {
unsigned int ctrl1;
err = regmap_bulk_read(hw->regmap,
ST_ILPS22QS_CTRL1_ADDR,
&ctrl1, 1);
if (err < 0)
goto unlock;
err = regmap_update_bits(hw->regmap,
ST_ILPS22QS_CTRL1_ADDR,
ST_ILPS22QS_ODR_MASK, 0);
if (err < 0)
goto unlock;
err = regmap_update_bits(hw->regmap,
ST_ILPS22QS_CTRL3_ADDR,
ST_ILPS22QS_AH_QVAR_EN_MASK, 0);
if (err < 0)
goto unlock;
err = regmap_update_bits(hw->regmap, ST_ILPS22QS_CTRL3_ADDR,
ST_ILPS22QS_AH_QVAR_P_AUTO_EN_MASK,
ST_ILPS22QS_SHIFT_VAL(interleave,
ST_ILPS22QS_AH_QVAR_P_AUTO_EN_MASK));
if (err < 0)
goto unlock;
err = regmap_update_bits(hw->regmap, ST_ILPS22QS_CTRL1_ADDR,
ST_ILPS22QS_ODR_MASK, ctrl1);
if (err < 0)
goto unlock;
} else if (hw->interleave) {
err = regmap_update_bits(hw->regmap, ST_ILPS22QS_CTRL3_ADDR,
ST_ILPS22QS_AH_QVAR_P_AUTO_EN_MASK, 0);
if (err < 0)
goto unlock;
}
hw->interleave = interleave;
unlock:
mutex_unlock(&hw->lock);
return err;
}
static int st_ilps22qs_hw_enable(struct st_ilps22qs_sensor *sensor, bool enable)
{
int ret = 0;
switch (sensor->id) {
case ST_ILPS22QS_QVAR:
case ST_ILPS22QS_PRESS:
ret = st_ilps22qs_set_interleave(sensor, enable);
break;
default:
return 0;
}
return ret;
}
static int st_ilps22qs_set_enable(struct st_ilps22qs_sensor *sensor,
bool enable)
{
struct st_ilps22qs_hw *hw = sensor->hw;
u8 odr = enable ? sensor->odr : 0;
int err;
err = st_ilps22qs_hw_enable(sensor, enable);
if (err < 0)
return err;
err = st_ilps22qs_set_odr(sensor, odr);
if (err < 0)
return err;
mutex_lock(&hw->lock);
if (enable) {
ktime_t ktime = ktime_set(0, 1000000000 / sensor->odr);
hrtimer_start(&sensor->hr_timer, ktime, HRTIMER_MODE_REL);
sensor->ktime = ktime;
hw->enable_mask |= BIT(sensor->id);
} else {
cancel_work_sync(&sensor->iio_work);
hrtimer_cancel(&sensor->hr_timer);
hw->enable_mask &= ~BIT(sensor->id);
}
if (!hw->interleave) {
err = regmap_update_bits(hw->regmap,
ST_ILPS22QS_CTRL3_ADDR,
ST_ILPS22QS_AH_QVAR_EN_MASK,
ST_ILPS22QS_SHIFT_VAL(!!(hw->enable_mask & BIT(ST_ILPS22QS_QVAR)),
ST_ILPS22QS_AH_QVAR_EN_MASK));
}
mutex_unlock(&hw->lock);
return err;
}
static int st_ilps22qs_init_sensors(struct st_ilps22qs_hw *hw)
{
int err;
/* soft reset the device on power on */
err = st_ilps22qs_update_locked(hw, ST_ILPS22QS_CTRL2_ADDR,
ST_ILPS22QS_SOFT_RESET_MASK, 1);
if (err < 0)
return err;
usleep_range(50, 60);
/* interleave disabled by default */
hw->interleave = false;
/* enable BDU */
return st_ilps22qs_update_locked(hw, ST_ILPS22QS_CTRL1_ADDR,
ST_ILPS22QS_BDU_MASK, 1);
}
static ssize_t
st_ilps22qs_get_sampling_frequency_avail(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int i, len = 0;
for (i = 0; i < st_ilps22qs_odr_table.size; i++) {
len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
st_ilps22qs_odr_table.odr_avl[i].hz);
}
buf[len - 1] = '\n';
return len;
}
static int st_ilps22qs_read_raw(struct iio_dev *iio_dev,
struct iio_chan_spec const *ch,
int *val, int *val2, long mask)
{
struct st_ilps22qs_sensor *sensor = iio_priv(iio_dev);
struct st_ilps22qs_hw *hw = sensor->hw;
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW: {
u8 data[4] = {};
int delay;
ret = iio_device_claim_direct_mode(iio_dev);
if (ret)
return ret;
ret = st_ilps22qs_set_enable(sensor, true);
if (ret < 0)
goto read_error;
delay = 1000000 / sensor->odr;
usleep_range(delay, 2 * delay);
ret = regmap_bulk_read(hw->regmap, ch->address, data,
ch->scan_type.realbits >> 3);
if (ret < 0)
goto read_error;
switch (sensor->id) {
case ST_ILPS22QS_PRESS:
*val = (s32)get_unaligned_le32(data);
break;
case ST_ILPS22QS_TEMP:
*val = (s16)get_unaligned_le16(data);
break;
case ST_ILPS22QS_QVAR:
*val = (s32)get_unaligned_le32(data);
break;
default:
ret = -ENODEV;
goto read_error;
}
read_error:
st_ilps22qs_set_enable(sensor, false);
iio_device_release_direct_mode(iio_dev);
if (ret < 0)
return ret;
ret = IIO_VAL_INT;
break;
}
case IIO_CHAN_INFO_SCALE:
switch (ch->type) {
case IIO_TEMP:
*val = 1000;
*val2 = sensor->gain;
ret = IIO_VAL_FRACTIONAL;
break;
case IIO_PRESSURE:
*val = 0;
*val2 = sensor->gain;
ret = IIO_VAL_INT_PLUS_NANO;
break;
case IIO_ALTVOLTAGE:
*val = 0;
*val2 = sensor->gain;
ret = IIO_VAL_INT_PLUS_NANO;
break;
default:
ret = -ENODEV;
break;
}
break;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = sensor->odr;
ret = IIO_VAL_INT;
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static int st_ilps22qs_write_raw(struct iio_dev *iio_dev,
struct iio_chan_spec const *ch,
int val, int val2, long mask)
{
struct st_ilps22qs_sensor *sensor = iio_priv(iio_dev);
int ret;
ret = iio_device_claim_direct_mode(iio_dev);
if (ret)
return ret;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
ret = st_ilps22qs_get_odr(sensor, val);
if (ret < 0)
goto exit_fail;
sensor->odr = st_ilps22qs_odr_table.odr_avl[ret].hz;
break;
default:
ret = -EINVAL;
break;
}
exit_fail:
iio_device_release_direct_mode(iio_dev);
return ret < 0 ? ret : 0;
}
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_ilps22qs_get_sampling_frequency_avail);
static struct attribute *st_ilps22qs_press_attributes[] = {
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
NULL,
};
static const struct attribute_group st_ilps22qs_press_attribute_group = {
.attrs = st_ilps22qs_press_attributes,
};
static const struct iio_info st_ilps22qs_press_info = {
.attrs = &st_ilps22qs_press_attribute_group,
.read_raw = st_ilps22qs_read_raw,
.write_raw = st_ilps22qs_write_raw,
.debugfs_reg_access = st_ilps22qs_reg_access,
};
static struct attribute *st_ilps22qs_temp_attributes[] = {
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
NULL,
};
static const struct attribute_group st_ilps22qs_temp_attribute_group = {
.attrs = st_ilps22qs_temp_attributes,
};
static const struct iio_info st_ilps22qs_temp_info = {
.attrs = &st_ilps22qs_temp_attribute_group,
.read_raw = st_ilps22qs_read_raw,
.write_raw = st_ilps22qs_write_raw,
.debugfs_reg_access = st_ilps22qs_reg_access,
};
static struct attribute *st_ilps22qs_qvar_attributes[] = {
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
NULL,
};
static const struct attribute_group st_ilps22qs_qvar_attribute_group = {
.attrs = st_ilps22qs_qvar_attributes,
};
static const struct iio_info st_ilps22qs_qvar_info = {
.attrs = &st_ilps22qs_qvar_attribute_group,
.read_raw = st_ilps22qs_read_raw,
.write_raw = st_ilps22qs_write_raw,
.debugfs_reg_access = st_ilps22qs_reg_access,
};
static int st_ilps22qs_preenable(struct iio_dev *iio_dev)
{
struct st_ilps22qs_sensor *sensor = iio_priv(iio_dev);
return st_ilps22qs_set_enable(sensor, true);
}
static int st_ilps22qs_postdisable(struct iio_dev *iio_dev)
{
struct st_ilps22qs_sensor *sensor = iio_priv(iio_dev);
return st_ilps22qs_set_enable(sensor, false);
}
static const struct iio_buffer_setup_ops st_ilps22qs_fifo_ops = {
.preenable = st_ilps22qs_preenable,
.postdisable = st_ilps22qs_postdisable,
};
static void st_ilps22qs_disable_regulator_action(void *_data)
{
struct st_ilps22qs_hw *hw = _data;
regulator_disable(hw->vddio_supply);
regulator_disable(hw->vdd_supply);
}
static int st_ilps22qs_power_enable(struct st_ilps22qs_hw *hw)
{
int err;
hw->vdd_supply = devm_regulator_get(hw->dev, "vdd");
if (IS_ERR(hw->vdd_supply)) {
if (PTR_ERR(hw->vdd_supply) != -EPROBE_DEFER)
dev_err(hw->dev, "Failed to get vdd regulator %d\n",
(int)PTR_ERR(hw->vdd_supply));
return PTR_ERR(hw->vdd_supply);
}
hw->vddio_supply = devm_regulator_get(hw->dev, "vddio");
if (IS_ERR(hw->vddio_supply)) {
if (PTR_ERR(hw->vddio_supply) != -EPROBE_DEFER)
dev_err(hw->dev, "Failed to get vddio regulator %d\n",
(int)PTR_ERR(hw->vddio_supply));
return PTR_ERR(hw->vddio_supply);
}
err = regulator_enable(hw->vdd_supply);
if (err) {
dev_err(hw->dev, "Failed to enable vdd regulator: %d\n", err);
return err;
}
err = regulator_enable(hw->vddio_supply);
if (err) {
regulator_disable(hw->vdd_supply);
return err;
}
err = devm_add_action_or_reset(hw->dev,
st_ilps22qs_disable_regulator_action,
hw);
if (err) {
dev_err(hw->dev,
"Failed to setup regulator cleanup action %d\n", err);
return err;
}
/*
* after the device is powered up, the ILPS22QS performs a 10 ms
* boot procedure to load the trimming parameters
*/
usleep_range(10000, 11000);
return 0;
}
static struct iio_dev *st_ilps22qs_alloc_iiodev(struct st_ilps22qs_hw *hw,
enum st_ilps22qs_sensor_id id)
{
struct st_ilps22qs_sensor *sensor;
struct iio_dev *iio_dev;
iio_dev = devm_iio_device_alloc(hw->dev, sizeof(*sensor));
if (!iio_dev)
return NULL;
iio_dev->modes = INDIO_DIRECT_MODE;
iio_dev->dev.parent = hw->dev;
sensor = iio_priv(iio_dev);
sensor->hw = hw;
sensor->id = id;
sensor->odr = st_ilps22qs_odr_table.odr_avl[0].hz;
switch (id) {
case ST_ILPS22QS_PRESS:
sensor->gain = ST_ILPS22QS_PRESS_FS_AVL_GAIN;
scnprintf(sensor->name, sizeof(sensor->name),
ST_ILPS22QS_DEV_NAME "_press");
iio_dev->channels = st_ilps22qs_press_channels;
iio_dev->num_channels = ARRAY_SIZE(st_ilps22qs_press_channels);
iio_dev->info = &st_ilps22qs_press_info;
break;
case ST_ILPS22QS_TEMP:
sensor->gain = ST_ILPS22QS_TEMP_FS_AVL_GAIN;
scnprintf(sensor->name, sizeof(sensor->name),
ST_ILPS22QS_DEV_NAME "_temp");
iio_dev->channels = st_ilps22qs_temp_channels;
iio_dev->num_channels = ARRAY_SIZE(st_ilps22qs_temp_channels);
iio_dev->info = &st_ilps22qs_temp_info;
break;
case ST_ILPS22QS_QVAR:
sensor->gain = ST_ILPS22QS_QVAR_FS_AVL_GAIN;
scnprintf(sensor->name, sizeof(sensor->name),
ST_ILPS22QS_DEV_NAME "_qvar");
iio_dev->channels = st_ilps22qs_qvar_channels;
iio_dev->num_channels = ARRAY_SIZE(st_ilps22qs_qvar_channels);
iio_dev->info = &st_ilps22qs_qvar_info;
break;
default:
return NULL;
}
iio_dev->name = sensor->name;
/* configure sensor hrtimer */
hrtimer_init(&sensor->hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
sensor->hr_timer.function = &st_ilps22qs_poll_function_read;
INIT_WORK(&sensor->iio_work, st_ilps22qs_poll_function_work);
return iio_dev;
}
int st_ilps22qs_probe(struct device *dev, struct regmap *regmap)
{
struct st_ilps22qs_hw *hw;
int err, i;
hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
if (!hw)
return -ENOMEM;
mutex_init(&hw->lock);
dev_set_drvdata(dev, (void *)hw);
hw->dev = dev;
hw->regmap = regmap;
err = st_ilps22qs_power_enable(hw);
if (err)
return err;
err = st_ilps22qs_check_whoami(hw);
if (err < 0)
return err;
err = st_ilps22qs_init_sensors(hw);
if (err < 0)
return err;
for (i = 0; i < ST_ILPS22QS_SENSORS_NUM; i++) {
#if KERNEL_VERSION(5, 13, 0) > LINUX_VERSION_CODE
struct iio_buffer *buffer;
#endif /* LINUX_VERSION_CODE */
hw->iio_devs[i] = st_ilps22qs_alloc_iiodev(hw, i);
if (!hw->iio_devs[i])
return -ENOMEM;
#if KERNEL_VERSION(5, 19, 0) <= LINUX_VERSION_CODE
err = devm_iio_kfifo_buffer_setup(hw->dev,
hw->iio_devs[i],
&st_ilps22qs_fifo_ops);
if (err)
return err;
#elif KERNEL_VERSION(5, 13, 0) <= LINUX_VERSION_CODE
err = devm_iio_kfifo_buffer_setup(hw->dev, hw->iio_devs[i],
INDIO_BUFFER_SOFTWARE,
&st_ilps22qs_fifo_ops);
if (err)
return err;
#else /* LINUX_VERSION_CODE */
buffer = devm_iio_kfifo_allocate(hw->dev);
if (!buffer)
return -ENOMEM;
iio_device_attach_buffer(hw->iio_devs[i], buffer);
hw->iio_devs[i]->modes |= INDIO_BUFFER_SOFTWARE;
hw->iio_devs[i]->setup_ops = &st_ilps22qs_fifo_ops;
#endif /* LINUX_VERSION_CODE */
err = devm_iio_device_register(hw->dev, hw->iio_devs[i]);
if (err)
return err;
}
err = st_ilps22qs_allocate_workqueue(hw);
if (err)
return err;
dev_info(dev, "device probed\n");
return 0;
}
EXPORT_SYMBOL(st_ilps22qs_probe);
int st_ilps22qs_remove(struct device *dev)
{
struct st_ilps22qs_hw *hw = dev_get_drvdata(dev);
struct st_ilps22qs_sensor *sensor;
int i;
for (i = 0; i < ST_ILPS22QS_SENSORS_NUM; i++) {
int err;
if (!hw->iio_devs[i])
continue;
sensor = iio_priv(hw->iio_devs[i]);
if (!(hw->enable_mask & BIT(sensor->id)))
continue;
err = st_ilps22qs_set_enable(sensor, false);
if (err < 0)
return err;
}
st_ilps22qs_flush_works(hw);
st_ilps22qs_destroy_workqueue(hw);
return 0;
}
EXPORT_SYMBOL(st_ilps22qs_remove);
static int __maybe_unused st_ilps22qs_suspend(struct device *dev)
{
struct st_ilps22qs_hw *hw = dev_get_drvdata(dev);
struct st_ilps22qs_sensor *sensor;
int i;
for (i = 0; i < ST_ILPS22QS_SENSORS_NUM; i++) {
int err;
if (!hw->iio_devs[i])
continue;
sensor = iio_priv(hw->iio_devs[i]);
if (!(hw->enable_mask & BIT(sensor->id)))
continue;
err = st_ilps22qs_set_odr(sensor, 0);
if (err < 0)
return err;
cancel_work_sync(&sensor->iio_work);
hrtimer_cancel(&sensor->hr_timer);
}
dev_info(dev, "Suspending device\n");
return 0;
}
static int __maybe_unused st_ilps22qs_resume(struct device *dev)
{
struct st_ilps22qs_hw *hw = dev_get_drvdata(dev);
struct st_ilps22qs_sensor *sensor;
int i;
dev_info(dev, "Resuming device\n");
for (i = 0; i < ST_ILPS22QS_SENSORS_NUM; i++) {
int err;
if (!hw->iio_devs[i])
continue;
sensor = iio_priv(hw->iio_devs[i]);
if (!(hw->enable_mask & BIT(sensor->id)))
continue;
err = st_ilps22qs_set_enable(sensor, true);
if (err < 0)
return err;
}
return 0;
}
const struct dev_pm_ops st_ilps22qs_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(st_ilps22qs_suspend, st_ilps22qs_resume)
};
EXPORT_SYMBOL(st_ilps22qs_pm_ops);
MODULE_AUTHOR("MEMS Software Solutions Team");
MODULE_DESCRIPTION("STMicroelectronics ilps22qs driver");
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,86 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* STMicroelectronics ilps22qs i2c driver
*
* Copyright 2023 STMicroelectronics Inc.
*
* MEMS Software Solutions Team
*/
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include "st_ilps22qs.h"
static const struct regmap_config st_ilps22qs_i2c_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
#if KERNEL_VERSION(6, 2, 0) <= LINUX_VERSION_CODE
static int st_ilps22qs_i2c_probe(struct i2c_client *client)
#else /* LINUX_VERSION_CODE */
static int st_ilps22qs_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
#endif /* LINUX_VERSION_CODE */
{
struct regmap *regmap;
regmap = devm_regmap_init_i2c(client, &st_ilps22qs_i2c_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&client->dev,
"Failed to register i2c regmap %d\n",
(int)PTR_ERR(regmap));
return PTR_ERR(regmap);
}
return st_ilps22qs_probe(&client->dev, regmap);
}
#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE
static void st_ilps22qs_i2c_remove(struct i2c_client *client)
{
st_ilps22qs_remove(&client->dev);
}
#else /* LINUX_VERSION_CODE */
static int st_ilps22qs_i2c_remove(struct i2c_client *client)
{
return st_ilps22qs_remove(&client->dev);
}
#endif /* LINUX_VERSION_CODE */
static const struct i2c_device_id st_ilps22qs_ids[] = {
{ ST_ILPS22QS_DEV_NAME },
{ ST_ILPS28QSW_DEV_NAME },
{}
};
MODULE_DEVICE_TABLE(i2c, st_ilps22qs_ids);
static const struct of_device_id st_ilps22qs_id_table[] = {
{ .compatible = "st," ST_ILPS22QS_DEV_NAME },
{ .compatible = "st," ST_ILPS28QSW_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(of, st_ilps22qs_id_table);
static struct i2c_driver st_ilps22qs_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "st_" ST_ILPS22QS_DEV_NAME "_i2c",
.pm = &st_ilps22qs_pm_ops,
.of_match_table = of_match_ptr(st_ilps22qs_id_table),
},
.probe = st_ilps22qs_i2c_probe,
.remove = st_ilps22qs_i2c_remove,
.id_table = st_ilps22qs_ids,
};
module_i2c_driver(st_ilps22qs_i2c_driver);
MODULE_AUTHOR("MEMS Software Solutions Team");
MODULE_DESCRIPTION("STMicroelectronics ilps22qs i2c driver");
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,6 @@
config INPUT_LSM303AGR
tristate "STM LSM303AGR sensor"
depends on I2C && SYSFS
help
This driver support the STMicroelectronics LSM303AGR sensor.

View File

@@ -0,0 +1,7 @@
#
# Makefile for the input misc lsm303agr driver.
#
# Each configuration option enables a list of files.
obj-$(CONFIG_INPUT_LSM303AGR) += lsm303agr_acc.o lsm303agr_mag.o lsm303agr_acc_i2c.o lsm303agr_mag_i2c.o

View File

@@ -0,0 +1,885 @@
/*
* STMicroelectronics lsm303agr_acc.c driver
*
* Copyright 2016 STMicroelectronics Inc.
*
* Giuseppe Barba <giuseppe.barba@st.com>
*
* Licensed under the GPL-2.
*/
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/version.h>
#include "lsm303agr_core.h"
#define LSM303AGR_ACC_DEV_NAME "lsm303agr_acc"
#define LSM303AGR_ACC_MIN_POLL_PERIOD_MS 1
/* I2C slave address */
#define LSM303AGR_ACC_I2C_SAD 0x29
/* Accelerometer Sensor Full Scale */
#define LSM303AGR_ACC_FS_MSK 0x20
#define LSM303AGR_ACC_G_2G 0x00
#define LSM303AGR_ACC_G_8G 0x20
#define AXISDATA_REG 0x28
#define WHOAMI_LSM303AGR_ACC 0x33
#define WHO_AM_I 0x0F
#define CTRL_REG1 0x20
#define CTRL_REG2 0x23
#define LSM303AGR_ACC_PM_OFF 0x00
#define LSM303AGR_ACC_ENABLE_ALL_AXIS 0x07
#define LSM303AGR_ACC_AXIS_MSK 0x07
#define LSM303AGR_ACC_ODR_MSK 0xf0
#define LSM303AGR_ACC_LP_MSK 0X08
#define LSM303AGR_ACC_HR_MSK 0X08
/* device opmode */
enum lsm303agr_acc_opmode {
LSM303AGR_ACC_OPMODE_NORMAL,
LSM303AGR_ACC_OPMODE_HR,
LSM303AGR_ACC_OPMODE_LP,
};
/* Device sensitivities [ug/digit] */
#define LSM303AGR_ACC_SENSITIVITY_NORMAL_2G 3900
#define LSM303AGR_ACC_SENSITIVITY_NORMAL_4G 7820
#define LSM303AGR_ACC_SENSITIVITY_NORMAL_8G 15630
#define LSM303AGR_ACC_SENSITIVITY_NORMAL_16G 46900
#define LSM303AGR_ACC_SENSITIVITY_HR_2G 980
#define LSM303AGR_ACC_SENSITIVITY_HR_4G 1950
#define LSM303AGR_ACC_SENSITIVITY_HR_8G 3900
#define LSM303AGR_ACC_SENSITIVITY_HR_16G 11720
#define LSM303AGR_ACC_SENSITIVITY_LP_2G 15630
#define LSM303AGR_ACC_SENSITIVITY_LP_4G 31260
#define LSM303AGR_ACC_SENSITIVITY_LP_8G 62520
#define LSM303AGR_ACC_SENSITIVITY_LP_16G 187580
/* Device shift values */
#define LSM303AGR_ACC_SHIFT_NORMAL_MODE 6
#define LSM303AGR_ACC_SHIFT_HR_MODE 4
#define LSM303AGR_ACC_SHIFT_LP_MODE 8
const struct {
u16 shift;
u32 sensitivity[4];
} lsm303agr_acc_opmode_table[] = {
{
/* normal mode */
LSM303AGR_ACC_SHIFT_NORMAL_MODE,
{
LSM303AGR_ACC_SENSITIVITY_NORMAL_2G,
LSM303AGR_ACC_SENSITIVITY_NORMAL_4G,
LSM303AGR_ACC_SENSITIVITY_NORMAL_8G,
LSM303AGR_ACC_SENSITIVITY_NORMAL_16G
}
},
{
/* hr mode */
LSM303AGR_ACC_SHIFT_HR_MODE,
{
LSM303AGR_ACC_SENSITIVITY_HR_2G,
LSM303AGR_ACC_SENSITIVITY_HR_4G,
LSM303AGR_ACC_SENSITIVITY_HR_8G,
LSM303AGR_ACC_SENSITIVITY_HR_16G
}
},
{
/* lp mode */
LSM303AGR_ACC_SHIFT_LP_MODE,
{
LSM303AGR_ACC_SENSITIVITY_LP_2G,
LSM303AGR_ACC_SENSITIVITY_LP_4G,
LSM303AGR_ACC_SENSITIVITY_LP_8G,
LSM303AGR_ACC_SENSITIVITY_LP_16G
}
}
};
#define LSM303AGR_ACC_ODR10 0x20 /* 10Hz output data rate */
#define LSM303AGR_ACC_ODR50 0x40 /* 50Hz output data rate */
#define LSM303AGR_ACC_ODR100 0x50 /* 100Hz output data rate */
#define LSM303AGR_ACC_ODR200 0x60 /* 200Hz output data rate */
/* read and write with mask a given register */
static int lsm303agr_acc_write_data_with_mask(struct lsm303agr_common_data *cdata,
u8 reg_addr, u8 mask, u8 *data)
{
int err;
u8 new_data, old_data = 0;
err = cdata->tf->read(cdata->dev, reg_addr, 1, &old_data);
if (err < 0)
return err;
new_data = ((old_data & (~mask)) | ((*data) & mask));
#ifdef LSM303AGR_ACC_DEBUG
dev_info(cdata->dev, "%s %02x o=%02x d=%02x n=%02x\n",
LSM303AGR_ACC_DEV_NAME, reg_addr, old_data, *data, new_data);
#endif
/* Save for caller usage the data that is about to be written */
*data = new_data;
if (new_data == old_data)
return 1;
return cdata->tf->write(cdata->dev, reg_addr, 1, &new_data);
}
static int lsm303agr_acc_input_init(struct lsm303agr_sensor_data *sdata,
const char* description)
{
int err;
sdata->input_dev = input_allocate_device();
if (!sdata->input_dev) {
dev_err(sdata->cdata->dev, "input device allocation failed\n");
return -ENOMEM;
}
sdata->input_dev->name = description;
sdata->input_dev->id.bustype = sdata->cdata->bus_type;
sdata->input_dev->dev.parent = sdata->cdata->dev;
input_set_drvdata(sdata->input_dev, sdata);
/* Set the input event characteristics of the probed sensor driver */
set_bit(INPUT_EVENT_TYPE, sdata->input_dev->evbit);
set_bit(INPUT_EVENT_TIME_MSB, sdata->input_dev->mscbit);
set_bit(INPUT_EVENT_TIME_LSB, sdata->input_dev->mscbit);
set_bit(INPUT_EVENT_X, sdata->input_dev->mscbit);
set_bit(INPUT_EVENT_Y, sdata->input_dev->mscbit);
set_bit(INPUT_EVENT_Z, sdata->input_dev->mscbit);
err = input_register_device(sdata->input_dev);
if (err) {
dev_err(sdata->cdata->dev,
"unable to register input device %s\n",
sdata->input_dev->name);
input_free_device(sdata->input_dev);
return err;
}
return 0;
}
struct {
unsigned int cutoff_ms;
unsigned int mask;
} lsm303agr_acc_odr_table[] = {
{ 5, LSM303AGR_ACC_ODR200 }, /* ODR = 200Hz */
{ 10, LSM303AGR_ACC_ODR100 }, /* ODR = 100Hz */
{ 20, LSM303AGR_ACC_ODR50 }, /* ODR = 50Hz */
{ 100, LSM303AGR_ACC_ODR10 }, /* ODR = 10Hz */
};
static int lsm303agr_acc_hw_init(struct lsm303agr_common_data *cdata)
{
int err;
u8 buf, wai = 0;
#ifdef LSM303AGR_ACC_DEBUG
pr_info("%s: hw init start\n", LSM303AGR_ACC_DEV_NAME);
#endif
err = cdata->tf->read(cdata->dev, WHO_AM_I, 1, &wai);
if (err < 0) {
dev_warn(cdata->dev, "Error reading WHO_AM_I\n");
goto error;
}
if (wai != WHOAMI_LSM303AGR_ACC) {
dev_err(cdata->dev,
"device unknown (0x%02x-0x%02x)\n",
WHOAMI_LSM303AGR_ACC, wai);
err = -1; /* choose the right coded error */
goto error;
}
buf = cdata->sensors[LSM303AGR_ACC_SENSOR].c_odr;
err = lsm303agr_acc_write_data_with_mask(cdata, CTRL_REG1,
LSM303AGR_ACC_ODR_MSK, &buf);
if (err < 0)
goto error;
cdata->hw_initialized = 1;
#ifdef LSM303AGR_ACC_DEBUG
pr_info("%s: hw init done\n", LSM303AGR_ACC_DEV_NAME);
#endif
return 0;
error:
cdata->hw_initialized = 0;
dev_err(cdata->dev, "hw init error 0x%02x: %d\n", buf, err);
return err;
}
static void lsm303agr_acc_device_power_off(struct lsm303agr_common_data *cdata)
{
int err;
u8 buf = LSM303AGR_ACC_PM_OFF;
err = lsm303agr_acc_write_data_with_mask(cdata, CTRL_REG1,
LSM303AGR_ACC_ODR_MSK, &buf);
if (err < 0)
dev_err(cdata->dev, "soft power off failed: %d\n", err);
if (cdata->hw_initialized)
cdata->hw_initialized = 0;
}
static int lsm303agr_acc_device_power_on(struct lsm303agr_common_data *cdata)
{
if (!cdata->hw_initialized) {
int err = lsm303agr_acc_hw_init(cdata);
if (err < 0) {
lsm303agr_acc_device_power_off(cdata);
return err;
}
}
return 0;
}
static int lsm303agr_acc_update_fs_range(struct lsm303agr_common_data *cdata,
u8 new_fs_range)
{
int err;
u8 indx;
u16 opmode;
unsigned int new_sensitivity;
struct lsm303agr_sensor_data *sdata;
sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR];
opmode = sdata->opmode;
switch (new_fs_range) {
case LSM303AGR_ACC_G_2G:
indx = 0;
break;
case LSM303AGR_ACC_G_8G:
indx = 2;
break;
default:
dev_err(cdata->dev, "invalid fs range requested: %u\n",
new_fs_range);
return -EINVAL;
}
/* Updates configuration register 4 which contains fs range setting */
err = lsm303agr_acc_write_data_with_mask(cdata, CTRL_REG2,
LSM303AGR_ACC_FS_MSK,
&new_fs_range);
if (err < 0)
goto error;
new_sensitivity = lsm303agr_acc_opmode_table[opmode].sensitivity[indx];
sdata->sensitivity = new_sensitivity;
#ifdef LSM303AGR_ACC_DEBUG
dev_info(cdata->dev, "%s shift=%d, sens=%d, opm=%d\n",
LSM303AGR_ACC_DEV_NAME, sdata->shift, sdata->sensitivity,
sdata->opmode);
#endif
return err;
error:
dev_err(cdata->dev, "update fs range failed %d\n", err);
return err;
}
static int lsm303agr_acc_update_odr(struct lsm303agr_common_data *cdata,
int poll_interval)
{
u8 buf;
int i, err = -1;
struct lsm303agr_sensor_data *sdata;
/**
* Following, looks for the longest possible odr
* interval od -x /dev/input/event0 scrolling the
* odr_table vector from the end (shortest interval) backward (longest
* interval), to support the poll_interval requested by the system.
* It must be the longest interval lower then the poll interval
*/
for (i = ARRAY_SIZE(lsm303agr_acc_odr_table) - 1; i >= 0; i--) {
if ((lsm303agr_acc_odr_table[i].cutoff_ms <= poll_interval) ||
(i == 0))
break;
}
sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR];
/* also save requested odr */
buf = (sdata->c_odr = lsm303agr_acc_odr_table[i].mask) |
LSM303AGR_ACC_ENABLE_ALL_AXIS;
/*
* If device is currently enabled, we need to write new
* configuration out to it
*/
if (atomic_read(&cdata->enabled)) {
err = lsm303agr_acc_write_data_with_mask(cdata, CTRL_REG1,
LSM303AGR_ACC_ODR_MSK |
LSM303AGR_ACC_AXIS_MSK,
&buf);
if (err < 0)
goto error;
}
#ifdef LSM303AGR_ACC_DEBUG
dev_info(cdata->dev, "update odr to 0x%02x,0x%02x: %d\n",
CTRL_REG1, buf, err);
#endif
return err;
error:
dev_err(cdata->dev, "update odr failed 0x%02x,0x%02x: %d\n",
CTRL_REG1, buf, err);
return err;
}
static int lsm303agr_acc_update_opmode(struct lsm303agr_common_data *cdata,
unsigned short opmode)
{
int err;
struct lsm303agr_sensor_data *sdata;
u8 lp = 0, hr = 0, indx = 0;
switch (opmode) {
case LSM303AGR_ACC_OPMODE_NORMAL:
break;
case LSM303AGR_ACC_OPMODE_HR:
hr = (1 << __ffs(LSM303AGR_ACC_LP_MSK));
break;
case LSM303AGR_ACC_OPMODE_LP:
lp = (1 << __ffs(LSM303AGR_ACC_HR_MSK));
break;
default:
return -EINVAL;
}
/* Set LP bit in CTRL_REG1 */
err = lsm303agr_acc_write_data_with_mask(cdata, CTRL_REG1,
LSM303AGR_ACC_LP_MSK, &lp);
if (err < 0)
goto error;
/* Set HR bit in CTRL_REG4 */
err = lsm303agr_acc_write_data_with_mask(cdata, CTRL_REG2,
LSM303AGR_ACC_HR_MSK,
&hr);
if (err < 0)
goto error;
/* Change platform data */
sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR];
sdata->opmode = opmode;
sdata->shift = lsm303agr_acc_opmode_table[opmode].shift;
switch (sdata->fs_range) {
case LSM303AGR_ACC_G_2G:
indx = 0;
break;
case LSM303AGR_ACC_G_8G:
indx = 2;
break;
}
sdata->sensitivity = lsm303agr_acc_opmode_table[opmode].sensitivity[indx];
#ifdef LSM303AGR_ACC_DEBUG
dev_info(cdata->dev, "%s shift=%d, sens=%d, opm=%d\n",
LSM303AGR_ACC_DEV_NAME, sdata->shift, sdata->sensitivity,
sdata->opmode);
#endif
return err;
error:
dev_err(cdata->dev, "update opmode failed: %d\n", err);
return err;
}
static int
lsm303agr_acc_get_acceleration_data(struct lsm303agr_common_data *cdata, int *xyz)
{
int err;
/* Data bytes from hardware xL, xH, yL, yH, zL, zH */
u8 acc_data[6];
/* x,y,z hardware data */
u32 sensitivity, shift;
err = cdata->tf->read(cdata->dev, AXISDATA_REG, 6, acc_data);
if (err < 0)
return err;
/* Get the current sensitivity and shift values */
sensitivity = cdata->sensors[LSM303AGR_ACC_SENSOR].sensitivity;
shift = cdata->sensors[LSM303AGR_ACC_SENSOR].shift;
/* Transform LSBs into ug */
xyz[0] = (s32)((s16)(acc_data[0] | (acc_data[1] << 8)) >> shift) * sensitivity;
xyz[1] = (s32)((s16)(acc_data[2] | (acc_data[3] << 8)) >> shift) * sensitivity;
xyz[2] = (s32)((s16)(acc_data[4] | (acc_data[5] << 8)) >> shift) * sensitivity;
#ifdef LSM303AGR_ACC_DEBUG
dev_info(cdata->dev, "%s read x=%d, y=%d, z=%d\n",
LSM303AGR_ACC_DEV_NAME, xyz[0], xyz[1], xyz[2]);
#endif
return err;
}
static void lsm303agr_acc_report_values(struct lsm303agr_common_data *cdata,
int *xyz, s64 timestamp)
{
struct lsm303agr_sensor_data *sdata;
sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR];
input_event(sdata->input_dev, INPUT_EVENT_TYPE, INPUT_EVENT_X, xyz[0]);
input_event(sdata->input_dev, INPUT_EVENT_TYPE, INPUT_EVENT_Y, xyz[1]);
input_event(sdata->input_dev, INPUT_EVENT_TYPE, INPUT_EVENT_Z, xyz[2]);
input_event(sdata->input_dev, INPUT_EVENT_TYPE, INPUT_EVENT_TIME_MSB,
timestamp >> 32);
input_event(sdata->input_dev, INPUT_EVENT_TYPE, INPUT_EVENT_TIME_LSB,
timestamp & 0xffffffff);
input_sync(sdata->input_dev);
}
int lsm303agr_acc_enable(struct lsm303agr_common_data *cdata)
{
if (!atomic_cmpxchg(&cdata->enabled, 0, 1)) {
int err;
struct lsm303agr_sensor_data *sdata;
mutex_lock(&cdata->lock);
sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR];
err = lsm303agr_acc_device_power_on(cdata);
if (err < 0) {
atomic_set(&cdata->enabled, 0);
return err;
}
schedule_delayed_work(&sdata->input_work,
msecs_to_jiffies(sdata->poll_interval));
mutex_unlock(&cdata->lock);
}
return 0;
}
EXPORT_SYMBOL(lsm303agr_acc_enable);
int lsm303agr_acc_disable(struct lsm303agr_common_data *cdata)
{
if (atomic_cmpxchg(&cdata->enabled, 1, 0)) {
struct lsm303agr_sensor_data *sdata;
sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR];
cancel_delayed_work_sync(&sdata->input_work);
mutex_lock(&cdata->lock);
lsm303agr_acc_device_power_off(cdata);
mutex_unlock(&cdata->lock);
}
return 0;
}
EXPORT_SYMBOL(lsm303agr_acc_disable);
static ssize_t attr_get_sched_num_acc(struct device *dev,
struct device_attribute *attr, char *buf)
{
int val;
struct lsm303agr_common_data *cdata = dev_get_drvdata(dev);
mutex_lock(&cdata->lock);
val = cdata->sensors[LSM303AGR_ACC_SENSOR].schedule_num;
mutex_unlock(&cdata->lock);
return sprintf(buf, "%d\n", val);
}
static ssize_t attr_set_sched_num_acc(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
unsigned long sched_num;
struct lsm303agr_common_data *cdata = dev_get_drvdata(dev);
if (kstrtoul(buf, 10, &sched_num))
return -EINVAL;
mutex_lock(&cdata->lock);
cdata->sensors[LSM303AGR_ACC_SENSOR].schedule_num = sched_num;
mutex_unlock(&cdata->lock);
return size;
}
static ssize_t attr_get_polling_rate_acc(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int val;
struct lsm303agr_common_data *cdata = dev_get_drvdata(dev);
mutex_lock(&cdata->lock);
val = cdata->sensors[LSM303AGR_ACC_SENSOR].poll_interval;
mutex_unlock(&cdata->lock);
return sprintf(buf, "%d\n", val);
}
static ssize_t attr_set_polling_rate_acc(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
unsigned long interval_ms;
struct lsm303agr_sensor_data *sdata;
struct lsm303agr_common_data *cdata = dev_get_drvdata(dev);
if (kstrtoul(buf, 10, &interval_ms))
return -EINVAL;
if (!interval_ms)
return -EINVAL;
sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR];
interval_ms = max_t(unsigned int, (unsigned int)interval_ms,
sdata->min_interval);
mutex_lock(&cdata->lock);
sdata->poll_interval = interval_ms;
lsm303agr_acc_update_odr(cdata, interval_ms);
mutex_unlock(&cdata->lock);
return size;
}
static ssize_t attr_get_range_acc(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct lsm303agr_sensor_data *sdata;
char range = 2;
struct lsm303agr_common_data *cdata = dev_get_drvdata(dev);
sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR];
mutex_lock(&cdata->lock);
switch (sdata->fs_range) {
case LSM303AGR_ACC_G_2G:
range = 2;
break;
case LSM303AGR_ACC_G_8G:
range = 8;
break;
}
mutex_unlock(&cdata->lock);
return sprintf(buf, "%d\n", range);
}
static ssize_t attr_set_range_acc(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
u8 range;
int err;
unsigned long val;
struct lsm303agr_sensor_data *sdata;
struct lsm303agr_common_data *cdata = dev_get_drvdata(dev);
sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR];
if (kstrtoul(buf, 10, &val))
return -EINVAL;
switch (val) {
case 2:
range = LSM303AGR_ACC_G_2G;
break;
case 8:
range = LSM303AGR_ACC_G_8G;
break;
default:
dev_err(cdata->dev,
"invalid range request: %lu, discarded\n", val);
return -EINVAL;
}
mutex_lock(&cdata->lock);
err = lsm303agr_acc_update_fs_range(cdata, range);
if (err < 0) {
mutex_unlock(&cdata->lock);
return err;
}
sdata->fs_range = range;
mutex_unlock(&cdata->lock);
dev_info(cdata->dev, "range set to: %lu g\n", val);
return size;
}
static ssize_t attr_get_opmode_acc(struct device *dev,
struct device_attribute *attr,
char *buf)
{
char opmode;
struct lsm303agr_common_data *cdata = dev_get_drvdata(dev);
mutex_lock(&cdata->lock);
opmode = cdata->sensors[LSM303AGR_ACC_SENSOR].opmode;
mutex_unlock(&cdata->lock);
return sprintf(buf, "%d\n", opmode);
}
static ssize_t attr_set_opmode_acc(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
int err;
u16 opmode;
unsigned long val;
struct lsm303agr_common_data *cdata = dev_get_drvdata(dev);
if (kstrtoul(buf, 10, &val))
return -EINVAL;
/* Check if argument is valid opmode */
switch (val) {
case LSM303AGR_ACC_OPMODE_NORMAL:
case LSM303AGR_ACC_OPMODE_HR:
case LSM303AGR_ACC_OPMODE_LP:
opmode = val;
break;
default:
dev_err(cdata->dev,
"invalid range request: %lu, discarded\n", val);
return -EINVAL;
}
mutex_lock(&cdata->lock);
err = lsm303agr_acc_update_opmode(cdata, opmode);
if (err < 0) {
mutex_unlock(&cdata->lock);
return err;
}
mutex_unlock(&cdata->lock);
dev_info(cdata->dev, "opmode set to: %u\n", opmode);
return size;
}
static ssize_t attr_get_enable_acc(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct lsm303agr_common_data *cdata = dev_get_drvdata(dev);
int val = atomic_read(&cdata->enabled);
return sprintf(buf, "%d\n", val);
}
static ssize_t attr_set_enable_acc(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct lsm303agr_common_data *cdata = dev_get_drvdata(dev);
unsigned long val;
if (kstrtoul(buf, 10, &val))
return -EINVAL;
if (val)
lsm303agr_acc_enable(cdata);
else
lsm303agr_acc_disable(cdata);
return size;
}
static struct device_attribute attributes[] = {
__ATTR(pollrate_ms, 0664, attr_get_polling_rate_acc,
attr_set_polling_rate_acc),
__ATTR(range, 0664, attr_get_range_acc, attr_set_range_acc),
__ATTR(opmode, 0664, attr_get_opmode_acc, attr_set_opmode_acc),
__ATTR(enable_device, 0664, attr_get_enable_acc, attr_set_enable_acc),
__ATTR(schedule_num, 0664, attr_get_sched_num_acc,
attr_set_sched_num_acc),
};
static int create_sysfs_interfaces(struct device *dev)
{
int i;
for (i = 0; i < ARRAY_SIZE(attributes); i++)
if (device_create_file(dev, attributes + i))
goto error;
return 0;
error:
for (; i >= 0; i--)
device_remove_file(dev, attributes + i);
dev_err(dev, "%s:Unable to create interface\n", __func__);
return -1;
}
static int remove_sysfs_interfaces(struct device *dev)
{
int i;
for (i = 0; i < ARRAY_SIZE(attributes); i++)
device_remove_file(dev, attributes + i);
return 0;
}
static void lsm303agr_acc_input_work_func(struct work_struct *work)
{
struct lsm303agr_common_data *cdata;
struct lsm303agr_sensor_data *sdata;
int err, xyz[3] = {};
sdata = container_of((struct delayed_work *)work,
struct lsm303agr_sensor_data, input_work);
cdata = sdata->cdata;
mutex_lock(&cdata->lock);
sdata->schedule_num++;
err = lsm303agr_acc_get_acceleration_data(cdata, xyz);
if (err < 0)
dev_err(cdata->dev, "get_acceleration_data failed\n");
else
lsm303agr_acc_report_values(cdata, xyz, lsm303agr_get_time_ns());
schedule_delayed_work(&sdata->input_work, msecs_to_jiffies(
sdata->poll_interval));
mutex_unlock(&cdata->lock);
}
static void lsm303agr_acc_input_cleanup(struct lsm303agr_common_data *cdata)
{
struct lsm303agr_sensor_data *sdata;
sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR];
input_unregister_device(sdata->input_dev);
input_free_device(sdata->input_dev);
}
int lsm303agr_acc_probe(struct lsm303agr_common_data *cdata)
{
int err;
struct lsm303agr_sensor_data *sdata;
mutex_lock(&cdata->lock);
/* init sensor data structure */
sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR];
sdata->cdata = cdata;
sdata->poll_interval = 100;
sdata->min_interval = LSM303AGR_ACC_MIN_POLL_PERIOD_MS;
err = lsm303agr_acc_device_power_on(cdata);
if (err < 0) {
dev_err(cdata->dev, "power on failed: %d\n", err);
goto err_power_off;
}
atomic_set(&cdata->enabled, 1);
err = lsm303agr_acc_update_fs_range(cdata, LSM303AGR_ACC_G_2G);
if (err < 0) {
dev_err(cdata->dev, "update_fs_range failed\n");
goto err_power_off;
}
err = lsm303agr_acc_update_odr(cdata, sdata->poll_interval);
if (err < 0) {
dev_err(cdata->dev, "update_odr failed\n");
goto err_power_off;
}
err = lsm303agr_acc_update_opmode(cdata, LSM303AGR_ACC_OPMODE_NORMAL);
if (err < 0) {
dev_err(cdata->dev, "update_opmode failed\n");
goto err_power_off;
}
err = lsm303agr_acc_input_init(sdata, LSM303AGR_ACC_DEV_NAME);
if (err < 0) {
dev_err(cdata->dev, "input init failed\n");
goto err_power_off;
}
INIT_DELAYED_WORK(&sdata->input_work, lsm303agr_acc_input_work_func);
err = create_sysfs_interfaces(cdata->dev);
if (err < 0) {
dev_err(cdata->dev,
"device LSM303AGR_ACC_DEV_NAME sysfs register failed\n");
goto err_input_cleanup;
}
lsm303agr_acc_device_power_off(cdata);
/* As default, do not report information */
atomic_set(&cdata->enabled, 0);
dev_info(cdata->dev, "%s: probed\n", LSM303AGR_ACC_DEV_NAME);
mutex_unlock(&cdata->lock);
return 0;
err_input_cleanup:
lsm303agr_acc_input_cleanup(cdata);
err_power_off:
lsm303agr_acc_device_power_off(cdata);
mutex_unlock(&cdata->lock);
pr_err("%s: Driver Init failed\n", LSM303AGR_ACC_DEV_NAME);
return err;
}
EXPORT_SYMBOL(lsm303agr_acc_probe);
void lsm303agr_acc_remove(struct lsm303agr_common_data *cdata)
{
lsm303agr_acc_disable(cdata);
lsm303agr_acc_input_cleanup(cdata);
remove_sysfs_interfaces(cdata->dev);
}
EXPORT_SYMBOL(lsm303agr_acc_remove);
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,207 @@
/*
* STMicroelectronics lsm303agr_acc_i2c.c driver
*
* Copyright 2016 STMicroelectronics Inc.
*
* Giuseppe Barba <giuseppe.barba@st.com>
*
* Licensed under the GPL-2.
*/
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/version.h>
#include "lsm303agr_core.h"
#define I2C_AUTO_INCREMENT 0x80
/* XXX: caller must hold cdata->lock */
static int lsm303agr_acc_i2c_read(struct device *dev, u8 reg_addr, int len,
u8 *data)
{
struct i2c_msg msg[2];
struct i2c_client *client = to_i2c_client(dev);
if (len > 1)
reg_addr |= I2C_AUTO_INCREMENT;
msg[0].addr = client->addr;
msg[0].flags = client->flags;
msg[0].len = 1;
msg[0].buf = &reg_addr;
msg[1].addr = client->addr;
msg[1].flags = client->flags | I2C_M_RD;
msg[1].len = len;
msg[1].buf = data;
return i2c_transfer(client->adapter, msg, 2);
}
/* XXX: caller must hold cdata->lock */
static int lsm303agr_acc_i2c_write(struct device *dev, u8 reg_addr, int len,
u8 *data)
{
u8 send[len + 1];
struct i2c_msg msg;
struct i2c_client *client = to_i2c_client(dev);
if (len > 1)
reg_addr |= I2C_AUTO_INCREMENT;
send[0] = reg_addr;
memcpy(&send[1], data, len * sizeof(u8));
len++;
msg.addr = client->addr;
msg.flags = client->flags;
msg.len = len;
msg.buf = send;
return i2c_transfer(client->adapter, &msg, 1);
}
/* I2C IO routines */
static const struct lsm303agr_transfer_function lsm303agr_acc_i2c_tf = {
.write = lsm303agr_acc_i2c_write,
.read = lsm303agr_acc_i2c_read,
};
#ifdef CONFIG_PM_SLEEP
static int lsm303agr_acc_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct lsm303agr_common_data *cdata = i2c_get_clientdata(client);
if (cdata->on_before_suspend)
return lsm303agr_acc_enable(cdata);
return 0;
}
static int lsm303agr_acc_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct lsm303agr_common_data *cdata = i2c_get_clientdata(client);
cdata->on_before_suspend = atomic_read(&cdata->enabled);
return lsm303agr_acc_disable(cdata);
}
static SIMPLE_DEV_PM_OPS(lsm303agr_acc_pm_ops,
lsm303agr_acc_suspend,
lsm303agr_acc_resume);
#define LSM303AGR_ACC_PM_OPS (&lsm303agr_acc_pm_ops)
#else /* CONFIG_PM_SLEEP */
#define LSM303AGR_ACC_PM_OPS NULL
#endif /* CONFIG_PM_SLEEP */
static int lsm303agr_acc_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int err;
struct lsm303agr_common_data *cdata;
dev_info(&client->dev, "probe start.\n");
/* Alloc Common data structure */
cdata = kzalloc(sizeof(struct lsm303agr_common_data), GFP_KERNEL);
if (!cdata) {
dev_err(&client->dev, "failed to allocate module data\n");
return -ENOMEM;
}
cdata->sensor_num = LSM303AGR_MAX_SENSORS_NUM;
cdata->dev = &client->dev;
cdata->name = client->name;
cdata->bus_type = BUS_I2C;
cdata->tf = &lsm303agr_acc_i2c_tf;
i2c_set_clientdata(client, cdata);
mutex_init(&cdata->lock);
err = lsm303agr_acc_probe(cdata);
if (err < 0) {
kfree(cdata);
return err;
}
return 0;
}
#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE
static void lsm303agr_acc_i2c_remove(struct i2c_client *client)
{
struct lsm303agr_common_data *cdata = i2c_get_clientdata(client);
dev_info(cdata->dev, "driver removing\n");
lsm303agr_acc_remove(cdata);
kfree(cdata);
}
#else
static int lsm303agr_acc_i2c_remove(struct i2c_client *client)
{
struct lsm303agr_common_data *cdata = i2c_get_clientdata(client);
dev_info(cdata->dev, "driver removing\n");
lsm303agr_acc_remove(cdata);
kfree(cdata);
return 0;
}
#endif
static const struct i2c_device_id lsm303agr_acc_i2c_id[] = {
{ "lsm303agr_acc", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, lsm303agr_acc_i2c_id);
#ifdef CONFIG_OF
static const struct of_device_id lsm303agr_acc_i2c_id_table[] = {
{.compatible = "st,lsm303agr_acc", },
{ },
};
MODULE_DEVICE_TABLE(of, lsm303agr_acc_i2c_id_table);
#endif /* CONFIG_OF */
static struct i2c_driver lsm303agr_acc_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "lsm303agr_acc",
.pm = LSM303AGR_ACC_PM_OPS,
#ifdef CONFIG_OF
.of_match_table = lsm303agr_acc_i2c_id_table,
#endif /* CONFIG_OF */
},
.probe = lsm303agr_acc_i2c_probe,
.remove = lsm303agr_acc_i2c_remove,
.id_table = lsm303agr_acc_i2c_id,
};
module_i2c_driver(lsm303agr_acc_i2c_driver);
MODULE_DESCRIPTION("lsm303agr accelerometer i2c driver");
MODULE_AUTHOR("Armando Visconti");
MODULE_AUTHOR("Matteo Dameno");
MODULE_AUTHOR("Denis Ciocca");
MODULE_AUTHOR("STMicroelectronics");
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,104 @@
/*
* STMicroelectronics lsm303agr driver
*
* Copyright 2016 STMicroelectronics Inc.
*
* Giuseppe Barba <giuseppe.barba@st.com>
*
* Licensed under the GPL-2.
*/
#ifndef __LSM303AGR_H__
#define __LSM303AGR_H__
#ifdef __KERNEL__
#define LSM303AGR_MAX_SENSORS_NUM 1
#define LSM303AGR_ACC_SENSOR 0 /* only this sensor */
#define LSM303AGR_MAG_SENSOR 0 /* only this sensor */
struct lsm303agr_common_data;
/* specific bus I/O functions */
struct lsm303agr_transfer_function {
int (*write) (struct device *dev, u8 reg_addr, int len, u8 *data);
int (*read) (struct device *dev, u8 reg_addr, int len, u8 *data);
};
#if defined(CONFIG_INPUT_LSM303AGR_SPI) || \
defined(CONFIG_INPUT_LSM303AGR_SPI_MODULE)
#define LSM303AGR_RX_MAX_LENGTH 500
#define LSM303AGR_TX_MAX_LENGTH 500
struct lsm303agr_transfer_buffer {
u8 rx_buf[LSM303AGR_RX_MAX_LENGTH];
u8 tx_buf[LSM303AGR_TX_MAX_LENGTH] ____cacheline_aligned;
};
#endif /* CONFIG_INPUT_LSM303AGR_SPI */
/* Sensor data */
struct lsm303agr_sensor_data {
struct lsm303agr_common_data *cdata;
const char* name;
s64 timestamp;
u8 enabled;
u32 c_odr;
u32 c_gain;
u8 sindex;
u8 sample_to_discard;
u32 poll_interval;
u32 min_interval;
u8 fs_range;
u32 sensitivity;
u16 shift;
u16 opmode;
struct input_dev *input_dev;
struct delayed_work input_work;
u32 schedule_num; /* Number of time work_input routine is called */
};
struct lsm303agr_common_data {
const char *name;
struct mutex lock;
struct device *dev;
int hw_initialized;
atomic_t enabled;
int on_before_suspend;
u8 sensor_num;
u16 bus_type;
struct lsm303agr_sensor_data sensors[LSM303AGR_MAX_SENSORS_NUM];
const struct lsm303agr_transfer_function *tf;
#if defined(CONFIG_INPUT_LSM303AGR_SPI) || \
defined(CONFIG_INPUT_LSM303AGR_SPI_MODULE)
struct lsm303agr_transfer_buffer tb;
#endif /* CONFIG_INPUT_LSM303AGR_SPI */
};
/* Input events used by lsm303agr driver */
#define INPUT_EVENT_TYPE EV_MSC
#define INPUT_EVENT_X MSC_SERIAL
#define INPUT_EVENT_Y MSC_PULSELED
#define INPUT_EVENT_Z MSC_GESTURE
#define INPUT_EVENT_TIME_MSB MSC_SCAN
#define INPUT_EVENT_TIME_LSB MSC_MAX
static inline s64 lsm303agr_get_time_ns(void)
{
return ktime_to_ns(ktime_get_boottime());
}
void lsm303agr_acc_remove(struct lsm303agr_common_data *cdata);
int lsm303agr_acc_probe(struct lsm303agr_common_data *cdata);
int lsm303agr_acc_enable(struct lsm303agr_common_data *cdata);
int lsm303agr_acc_disable(struct lsm303agr_common_data *cdata);
void lsm303agr_mag_remove(struct lsm303agr_common_data *cdata);
int lsm303agr_mag_probe(struct lsm303agr_common_data *cdata);
int lsm303agr_mag_enable(struct lsm303agr_common_data *cdata);
int lsm303agr_mag_disable(struct lsm303agr_common_data *cdata);
#endif /* __KERNEL__ */
#endif /* __LSM303AGR_H__ */

View File

@@ -0,0 +1,556 @@
/*
* STMicroelectronics lsm303agr_mag.c driver
*
* Copyright 2016 STMicroelectronics Inc.
*
* Giuseppe Barba <giuseppe.barba@st.com>
*
* Licensed under the GPL-2.
*/
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/version.h>
#include "lsm303agr_core.h"
#define LSM303AGR_MAG_DEV_NAME "lsm303agr_mag"
/* DEVICE REGISTERS */
#define WHO_AM_I 0x4F
#define CFG_REG_A 0x60
#define AXISDATA_REG 0x68
#define WHOAMI_LSM303AGR_MAG 0x40
/* Device operating modes */
#define MD_CONTINUOS_MODE 0x00
#define MD_SINGLE_MODE 0x01
#define MD_IDLE1_MODE 0x02
#define MD_IDLE2_MODE 0x03
#define LSM303AGR_MAG_MODE_MSK 0x03
/* Device ODRs */
#define LSM303AGR_MAG_ODR10_HZ 0x00
#define LSM303AGR_MAG_ODR20_HZ 0x04
#define LSM303AGR_MAG_ODR50_HZ 0x08
#define LSM303AGR_MAG_ODR100_HZ 0x0C
#define LSM303AGR_MAG_ODR_MSK 0x0C
#define LSM303AGR_MAG_SENSITIVITY 1500 /* uGa/LSB */
/* ODR table */
struct {
u32 time_ms;
u32 reg_val;
} lsm303agr_mag_odr_table[] = {
{ 10, LSM303AGR_MAG_ODR100_HZ }, /* ODR = 100Hz */
{ 20, LSM303AGR_MAG_ODR50_HZ }, /* ODR = 50Hz */
{ 50, LSM303AGR_MAG_ODR20_HZ }, /* ODR = 20Hz */
{ 100, LSM303AGR_MAG_ODR10_HZ }, /* ODR = 10Hz */
};
/* read and write with mask a given register */
static int lsm303agr_mag_write_data_with_mask(struct lsm303agr_common_data *cdata,
u8 reg_addr, u8 mask, u8 *data)
{
int err;
u8 new_data, old_data = 0;
err = cdata->tf->read(cdata->dev, reg_addr, 1, &old_data);
if (err < 0)
return err;
new_data = ((old_data & (~mask)) | ((*data) & mask));
#ifdef LSM303AGR_MAG_DEBUG
dev_info(cdata->dev, "%s %02x o=%02x d=%02x n=%02x\n",
LSM303AGR_MAG_DEV_NAME, reg_addr, old_data, *data, new_data);
#endif
/* Save for caller usage the data that is about to be written */
*data = new_data;
if (new_data == old_data)
return 1;
return cdata->tf->write(cdata->dev, reg_addr, 1, &new_data);
}
int lsm303agr_mag_input_init(struct lsm303agr_sensor_data *sdata,
const char* description)
{
int err;
sdata->input_dev = input_allocate_device();
if (!sdata->input_dev) {
dev_err(sdata->cdata->dev, "input device allocation failed\n");
return -ENOMEM;
}
sdata->input_dev->name = description;
sdata->input_dev->id.bustype = sdata->cdata->bus_type;
sdata->input_dev->dev.parent = sdata->cdata->dev;
input_set_drvdata(sdata->input_dev, sdata);
/* Set the input event characteristics of the probed sensor driver */
set_bit(INPUT_EVENT_TYPE, sdata->input_dev->evbit );
set_bit(INPUT_EVENT_TIME_MSB, sdata->input_dev->mscbit);
set_bit(INPUT_EVENT_TIME_LSB, sdata->input_dev->mscbit);
set_bit(INPUT_EVENT_X, sdata->input_dev->mscbit);
set_bit(INPUT_EVENT_Y, sdata->input_dev->mscbit);
set_bit(INPUT_EVENT_Z, sdata->input_dev->mscbit);
err = input_register_device(sdata->input_dev);
if (err) {
dev_err(sdata->cdata->dev,
"unable to register input device %s\n",
sdata->input_dev->name);
input_free_device(sdata->input_dev);
return err;
}
return 0;
}
/* Check if WHO_AM_I is correct */
static int lsm303agr_mag_check_wai(struct lsm303agr_common_data *cdata)
{
int err;
u8 wai;
#ifdef LSM303AGR_MAG_DEBUG
pr_info("%s: check WAI start\n", LSM303AGR_MAG_DEV_NAME);
#endif
err = cdata->tf->read(cdata->dev, WHO_AM_I, 1, &wai);
if (err < 0) {
dev_warn(cdata->dev,
"Error reading WHO_AM_I: is device available/working?\n");
goto error;
}
if (wai != WHOAMI_LSM303AGR_MAG) {
dev_err(cdata->dev,
"device unknown. Expected: 0x%02x," " Replies: 0x%02x\n",
WHOAMI_LSM303AGR_MAG, wai);
err = -1; /* choose the right coded error */
goto error;
}
cdata->hw_initialized = 1;
#ifdef LSM303AGR_MAG_DEBUG
pr_info("%s: check WAI done\n", LSM303AGR_MAG_DEV_NAME);
#endif
return 0;
error:
cdata->hw_initialized = 0;
dev_err(cdata->dev,
"check WAI error 0x%02x,0x%02x: %d\n", WHO_AM_I, wai, err);
return err;
}
static int lsm303agr_mag_set_odr(struct lsm303agr_common_data *cdata, u8 odr)
{
u8 odr_reg;
int err = -1, i;
struct lsm303agr_sensor_data *sdata;
/**
* Following, looks for the longest possible odr interval scrolling the
* odr_table vector from the end (shortest interval) backward
* (longest interval), to support the poll_interval requested
* by the system. It must be the longest interval lower
* than the poll interval
*/
for (i = ARRAY_SIZE(lsm303agr_mag_odr_table) - 1; i >= 0; i--) {
if ((lsm303agr_mag_odr_table[i].time_ms <= odr) || (i == 0))
break;
}
odr_reg = lsm303agr_mag_odr_table[i].reg_val;
sdata = &cdata->sensors[LSM303AGR_MAG_SENSOR];
sdata->poll_interval = sdata->c_odr = lsm303agr_mag_odr_table[i].time_ms;
/* If device is currently enabled, we need to write new
* configuration out to it */
if (atomic_read(&cdata->enabled)) {
err = lsm303agr_mag_write_data_with_mask(cdata, CFG_REG_A,
LSM303AGR_MAG_ODR_MSK,
&odr_reg);
if (err < 0)
goto error;
#ifdef LSM303AGR_MAG_DEBUG
dev_info(cdata->dev, "update odr to 0x%02x,0x%02x: %d\n",
CFG_REG_A, odr_reg, err);
#endif
}
return lsm303agr_mag_odr_table[i].time_ms;
error:
dev_err(cdata->dev, "set odr failed 0x%02x,0x%02x: %d\n",
CFG_REG_A, odr_reg, err);
return err;
}
static int lsm303agr_mag_set_device_mode(struct lsm303agr_common_data *cdata,
u8 mode)
{
int err;
err = lsm303agr_mag_write_data_with_mask(cdata, CFG_REG_A,
LSM303AGR_MAG_MODE_MSK,
&mode);
if (err < 0)
goto error;
#ifdef LSM303AGR_MAG_DEBUG
dev_info(cdata->dev, "update mode to 0x%02x,0x%02x: %d\n",
CFG_REG_A, mode, err);
#endif
return 0;
error:
dev_err(cdata->dev,
"set continuos mode failed 0x%02x,0x%02x: %d\n",
CFG_REG_A, mode, err);
return err;
}
/* Set device in continuos mode */
int lsm303agr_mag_enable(struct lsm303agr_common_data *cdata)
{
struct lsm303agr_sensor_data *sdata;
int err;
mutex_lock(&cdata->lock);
/* Set the magnetometer in continuos mode */
err = lsm303agr_mag_set_device_mode(cdata, MD_CONTINUOS_MODE);
if (err < 0) {
dev_err(cdata->dev, "set_continuos failed: %d\n",
err);
mutex_unlock(&cdata->lock);
return err;
}
atomic_set(&cdata->enabled, 1);
sdata = &cdata->sensors[LSM303AGR_MAG_SENSOR];
if (lsm303agr_mag_set_odr(cdata, sdata->c_odr) < 0) {
mutex_unlock(&cdata->lock);
return -1;
}
/* Start scheduling input */
schedule_delayed_work(&sdata->input_work,
msecs_to_jiffies(sdata->poll_interval));
mutex_unlock(&cdata->lock);
return 0;
}
EXPORT_SYMBOL(lsm303agr_mag_enable);
/* Set device in idle mode */
int lsm303agr_mag_disable(struct lsm303agr_common_data *cdata)
{
if (atomic_cmpxchg(&cdata->enabled, 1, 0)) {
int err;
struct lsm303agr_sensor_data *sdata;
sdata = &cdata->sensors[LSM303AGR_MAG_SENSOR];
cancel_delayed_work_sync(&sdata->input_work);
mutex_lock(&cdata->lock);
/* Set the magnetometer in idle mode */
err = lsm303agr_mag_set_device_mode(cdata, MD_IDLE2_MODE);
if (err < 0) {
dev_err(cdata->dev, "set_idle failed: %d\n",
err);
mutex_unlock(&cdata->lock);
return err;
}
mutex_unlock(&cdata->lock);
}
return 0;
}
EXPORT_SYMBOL(lsm303agr_mag_disable);
static void lsm303agr_mag_report_event(struct lsm303agr_common_data *cdata,
int *xyz, s64 timestamp)
{
struct lsm303agr_sensor_data *sdata;
sdata = &cdata->sensors[LSM303AGR_MAG_SENSOR];
input_event(sdata->input_dev, INPUT_EVENT_TYPE, INPUT_EVENT_X, xyz[0]);
input_event(sdata->input_dev, INPUT_EVENT_TYPE, INPUT_EVENT_Y, xyz[1]);
input_event(sdata->input_dev, INPUT_EVENT_TYPE, INPUT_EVENT_Z, xyz[2]);
input_event(sdata->input_dev, INPUT_EVENT_TYPE, INPUT_EVENT_TIME_MSB,
timestamp >> 32);
input_event(sdata->input_dev, INPUT_EVENT_TYPE, INPUT_EVENT_TIME_LSB,
timestamp & 0xffffffff);
input_sync(sdata->input_dev);
}
static int lsm303agr_mag_get_data(struct lsm303agr_common_data *cdata,
int *xyz)
{
int err;
/* Data bytes from hardware xL, xH, yL, yH, zL, zH */
u8 mag_data[6];
err = cdata->tf->read(cdata->dev, AXISDATA_REG, 6, mag_data);
if (err < 0)
return err;
/* Transform LSBs into ug */
xyz[0] = (s32)((s16)(mag_data[0] | (mag_data[1] << 8)));
xyz[0] *= LSM303AGR_MAG_SENSITIVITY;
xyz[1] = (s32)((s16)(mag_data[2] | (mag_data[3] << 8)));
xyz[1] *= LSM303AGR_MAG_SENSITIVITY;
xyz[2] = (s32)((s16)(mag_data[4] | (mag_data[5] << 8)));
xyz[2] *= LSM303AGR_MAG_SENSITIVITY;
#ifdef LSM303AGR_MAG_DEBUG
dev_info(cdata->dev, "%s read x=%d, y=%d, z=%d\n",
LSM303AGR_MAG_DEV_NAME, xyz[0], xyz[1], xyz[2]);
#endif
return err;
}
static void lsm303agr_mag_input_work_func(struct work_struct *work)
{
struct lsm303agr_common_data *cdata;
struct lsm303agr_sensor_data *sdata;
int err, xyz[3] = {};
sdata = container_of((struct delayed_work *)work,
struct lsm303agr_sensor_data, input_work);
cdata = sdata->cdata;
mutex_lock(&cdata->lock);
sdata->schedule_num++;
err = lsm303agr_mag_get_data(cdata, xyz);
if (err < 0)
dev_err(cdata->dev, "get_mag_data failed\n");
else
lsm303agr_mag_report_event(cdata, xyz,
lsm303agr_get_time_ns());
schedule_delayed_work(&sdata->input_work,
msecs_to_jiffies(sdata->poll_interval));
mutex_unlock(&cdata->lock);
}
static void lsm303agr_mag_input_cleanup(struct lsm303agr_common_data *cdata)
{
struct lsm303agr_sensor_data *sdata;
sdata = &cdata->sensors[LSM303AGR_MAG_SENSOR];
input_unregister_device(sdata->input_dev);
input_free_device(sdata->input_dev);
}
/* SYSFS: set val to polling_ms ATTR */
static ssize_t attr_get_polling_rate_mag(struct device *dev,
struct device_attribute *attr,
char *buf)
{
u32 val = 0;
struct lsm303agr_sensor_data *sdata;
struct lsm303agr_common_data *cdata = dev_get_drvdata(dev);
sdata = &cdata->sensors[LSM303AGR_MAG_SENSOR];
/* read from platform data */
mutex_lock(&cdata->lock);
val = sdata->poll_interval;
mutex_unlock(&cdata->lock);
return sprintf(buf, "%d\n", val);
}
static ssize_t attr_set_polling_rate_mag(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
unsigned long val = 0;
struct lsm303agr_common_data *cdata = dev_get_drvdata(dev);
if (kstrtoul(buf, 10, &val))
return -EINVAL;
if (!val)
return -EINVAL;
mutex_lock(&cdata->lock);
/* set ODR */
val = lsm303agr_mag_set_odr(cdata, val);
if (val < 0) {
mutex_unlock(&cdata->lock);
return -1;
}
/* write to platform data */
cdata->sensors[LSM303AGR_MAG_SENSOR].poll_interval = val;
mutex_unlock(&cdata->lock);
return size;
}
/* SYSFS: set val to enable_device ATTR */
static ssize_t attr_get_enable_mag(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct lsm303agr_common_data *cdata = dev_get_drvdata(dev);
int val = atomic_read(&cdata->enabled);
return sprintf(buf, "%d\n", val);
}
/* SYSFS: get val from enable_device ATTR */
static ssize_t attr_set_enable_mag(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
unsigned long val;
struct lsm303agr_common_data *cdata = dev_get_drvdata(dev);
if (kstrtoul(buf, 10, &val))
return -EINVAL;
if (val)
lsm303agr_mag_enable(cdata);
else
lsm303agr_mag_disable(cdata);
return size;
}
static struct device_attribute lsm303agr_mag_attributes[] = {
__ATTR(pollrate_ms, 0664, attr_get_polling_rate_mag,
attr_set_polling_rate_mag),
__ATTR(enable_device, 0664, attr_get_enable_mag, attr_set_enable_mag),
};
static int create_sysfs_interfaces(struct device *dev)
{
int i;
for (i = 0; i < ARRAY_SIZE(lsm303agr_mag_attributes); i++)
if (device_create_file(dev, lsm303agr_mag_attributes + i))
goto error;
return 0;
error:
for (; i >= 0; i--)
device_remove_file(dev, lsm303agr_mag_attributes + i);
dev_err(dev, "%s:Unable to create interface\n", __func__);
return -1;
}
static int remove_sysfs_interfaces(struct device *dev)
{
int i;
for (i = 0; i < ARRAY_SIZE(lsm303agr_mag_attributes); i++)
device_remove_file(dev, lsm303agr_mag_attributes + i);
return 0;
}
int lsm303agr_mag_probe(struct lsm303agr_common_data *cdata)
{
int err;
struct lsm303agr_sensor_data *sdata;
mutex_lock(&cdata->lock);
/* init sensor data structure */
sdata = &cdata->sensors[LSM303AGR_MAG_SENSOR];
sdata->cdata = cdata;
/* Check WHO_AM_I */
err = lsm303agr_mag_check_wai(cdata);
if (err < 0) {
dev_err(cdata->dev, "check WAI failed\n");
mutex_unlock(&cdata->lock);
return err;
}
/* Set device ODR to 100ms (10Hz) */
err = lsm303agr_mag_set_odr(cdata, 100);
if (err < 0) {
dev_err(cdata->dev, "Set ODR On failed\n");
mutex_unlock(&cdata->lock);
return err;
}
/* Disable Magnetometer to save power */
mutex_unlock(&cdata->lock);
err = lsm303agr_mag_disable(cdata);
if (err < 0) {
dev_err(cdata->dev, "Power On failed\n");
mutex_unlock(&cdata->lock);
return err;
}
mutex_lock(&cdata->lock);
/* Init the input framework */
err = lsm303agr_mag_input_init(sdata, LSM303AGR_MAG_DEV_NAME);
if (err < 0) {
dev_err(cdata->dev, "input init failed\n");
mutex_unlock(&cdata->lock);
return err;
}
INIT_DELAYED_WORK(&sdata->input_work, lsm303agr_mag_input_work_func);
/* Create SYSFS interface */
err = create_sysfs_interfaces(cdata->dev);
if (err < 0) {
dev_err(cdata->dev,
"device LSM303AGR_MAG_DEV_NAME sysfs register failed\n");
mutex_unlock(&cdata->lock);
return err;
}
dev_info(cdata->dev, "%s: probed\n", LSM303AGR_MAG_DEV_NAME);
mutex_unlock(&cdata->lock);
return 0;
}
EXPORT_SYMBOL(lsm303agr_mag_probe);
void lsm303agr_mag_remove(struct lsm303agr_common_data *cdata)
{
lsm303agr_mag_disable(cdata);
lsm303agr_mag_input_cleanup(cdata);
remove_sysfs_interfaces(cdata->dev);
}
EXPORT_SYMBOL(lsm303agr_mag_remove);
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,210 @@
/*
* STMicroelectronics lsm303agr_mag_i2c.c driver
*
* Copyright 2016 STMicroelectronics Inc.
*
* Giuseppe Barba <giuseppe.barba@st.com>
*
* Licensed under the GPL-2.
*/
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/version.h>
#include "lsm303agr_core.h"
#define I2C_AUTO_INCREMENT 0x80
/* XXX: caller must hold cdata->lock */
static int lsm303agr_mag_i2c_read(struct device *dev, u8 reg_addr, int len,
u8 *data)
{
struct i2c_msg msg[2];
struct i2c_client *client = to_i2c_client(dev);
if (len > 1)
reg_addr |= I2C_AUTO_INCREMENT;
msg[0].addr = client->addr;
msg[0].flags = client->flags;
msg[0].len = 1;
msg[0].buf = &reg_addr;
msg[1].addr = client->addr;
msg[1].flags = client->flags | I2C_M_RD;
msg[1].len = len;
msg[1].buf = data;
return i2c_transfer(client->adapter, msg, 2);
}
/* XXX: caller must hold cdata->lock */
static int lsm303agr_mag_i2c_write(struct device *dev, u8 reg_addr, int len,
u8 *data)
{
u8 send[len + 1];
struct i2c_msg msg;
struct i2c_client *client = to_i2c_client(dev);
if (len > 1)
reg_addr |= I2C_AUTO_INCREMENT;
send[0] = reg_addr;
memcpy(&send[1], data, len * sizeof(u8));
len++;
msg.addr = client->addr;
msg.flags = client->flags;
msg.len = len;
msg.buf = send;
return i2c_transfer(client->adapter, &msg, 1);
}
/* I2C IO routines */
static const struct lsm303agr_transfer_function lsm303agr_mag_i2c_tf = {
.write = lsm303agr_mag_i2c_write,
.read = lsm303agr_mag_i2c_read,
};
#ifdef CONFIG_PM_SLEEP
static int lsm303agr_mag_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct lsm303agr_common_data *cdata = i2c_get_clientdata(client);
if (cdata->on_before_suspend)
return lsm303agr_mag_enable(cdata);
return 0;
}
static int lsm303agr_mag_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct lsm303agr_common_data *cdata = i2c_get_clientdata(client);
cdata->on_before_suspend = atomic_read(&cdata->enabled);
return lsm303agr_mag_disable(cdata);
}
static SIMPLE_DEV_PM_OPS(lsm303agr_mag_pm_ops,
lsm303agr_mag_suspend,
lsm303agr_mag_resume);
#define LSM303AGR_MAG_PM_OPS (&lsm303agr_mag_pm_ops)
#else /* CONFIG_PM_SLEEP */
#define LSM303AGR_MAG_PM_OPS NULL
#endif /* CONFIG_PM_SLEEP */
static int lsm303agr_mag_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int err;
struct lsm303agr_common_data *cdata;
dev_info(&client->dev, "probe start.\n");
/* Alloc Common data structure */
cdata = kzalloc(sizeof(struct lsm303agr_common_data), GFP_KERNEL);
if (cdata == NULL) {
dev_err(&client->dev,
"failed to allocate memory for module data\n");
mutex_unlock(&cdata->lock);
return -ENOMEM;
}
cdata->sensor_num = LSM303AGR_MAX_SENSORS_NUM;
cdata->dev = &client->dev;
cdata->name = client->name;
cdata->bus_type = BUS_I2C;
cdata->tf = &lsm303agr_mag_i2c_tf;
i2c_set_clientdata(client, cdata);
mutex_init(&cdata->lock);
err = lsm303agr_mag_probe(cdata);
if (err < 0) {
kfree(cdata);
return err;
}
return 0;
}
#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE
static void lsm303agr_mag_i2c_remove(struct i2c_client *client)
{
struct lsm303agr_common_data *cdata = i2c_get_clientdata(client);
dev_info(cdata->dev, "driver removing\n");
lsm303agr_mag_remove(cdata);
kfree(cdata);
}
#else
static int lsm303agr_mag_i2c_remove(struct i2c_client *client)
{
struct lsm303agr_common_data *cdata = i2c_get_clientdata(client);
dev_info(cdata->dev, "driver removing\n");
lsm303agr_mag_remove(cdata);
kfree(cdata);
return 0;
}
#endif
static const struct i2c_device_id lsm303agr_mag_i2c_id[] = {
{ "lsm303agr_mag", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, lsm303agr_mag_i2c_id);
#ifdef CONFIG_OF
static const struct of_device_id lsm303agr_mag_i2c_id_table[] = {
{.compatible = "st,lsm303agr_mag", },
{ },
};
MODULE_DEVICE_TABLE(of, lsm303agr_mag_i2c_id_table);
#endif /* CONFIG_OF */
static struct i2c_driver lsm303agr_mag_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "lsm303agr_mag",
.pm = LSM303AGR_MAG_PM_OPS,
#ifdef CONFIG_OF
.of_match_table = lsm303agr_mag_i2c_id_table,
#endif /* CONFIG_OF */
},
.probe = lsm303agr_mag_i2c_probe,
.remove = lsm303agr_mag_i2c_remove,
.id_table = lsm303agr_mag_i2c_id,
};
module_i2c_driver(lsm303agr_mag_i2c_driver);
MODULE_DESCRIPTION("lsm303agr magnetometer i2c driver");
MODULE_AUTHOR("Armando Visconti");
MODULE_AUTHOR("Matteo Dameno");
MODULE_AUTHOR("Denis Ciocca");
MODULE_AUTHOR("STMicroelectronics");
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,228 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for Rtl PHY
*
* Author: Huang Yunxiang <huangyunxiang@cigtech.com>
*
* Copyright 2024 cig, Inc.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/bitfield.h>
#include <linux/phy.h>
#define PHY_ID_RTL8221D 0x001CC841
#define BIT_0 0x0001
#define BIT_1 0x0002
#define BIT_2 0x0004
#define BIT_3 0x0008
#define BIT_4 0x0010
#define BIT_5 0x0020
#define BIT_6 0x0040
#define BIT_7 0x0080
#define BIT_8 0x0100
#define BIT_9 0x0200
#define BIT_10 0x0400
#define BIT_11 0x0800
#define BIT_12 0x1000
#define BIT_13 0x2000
#define BIT_14 0x4000
#define BIT_15 0x8000
static int rtl8221d_config_aneg(struct phy_device *phydev)
{
return 0;
}
static u32 Rtl8226b_is_link(struct phy_device *phydev)
{
int phydata = 0;
int i = 0;
// must read twice
for(i=0;i<2;i++)
{
phydata = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xA402);
}
phydev->link = (phydata & BIT_2) ? (1) : (0);
return 0;
}
static int rtl8221d_read_status(struct phy_device *phydev)
{
int phydata, speed_grp, speed;
Rtl8226b_is_link(phydev);
if (phydev->link)
{
phydata = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xA434);
speed_grp = (phydata & (BIT_9 | BIT_10)) >> 9;
speed = (phydata & (BIT_4 | BIT_5)) >> 4;
switch(speed_grp)
{
case 0:
{
switch(speed)
{
case 1:
phydev->speed = SPEED_100;
break;
case 2:
phydev->speed = SPEED_1000;
break;
default:
phydev->speed = SPEED_10;
break;
}
break;
}
case 1:
{
switch(speed)
{
case 1:
phydev->speed = SPEED_2500;
break;
case 3:
phydev->speed = SPEED_1000; // 2.5G lite
break;
default:
phydev->speed = SPEED_10;
break;
}
break;
}
default:
phydev->speed = SPEED_10;
break;
}
}
else
{
phydev->speed = SPEED_10;
}
phydata = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xA434);
phydev->duplex = (phydata & BIT_3) ? (DUPLEX_FULL) : (DUPLEX_HALF);
return 0;
}
static int rtl8221d_config_init(struct phy_device *phydev)
{
int err;
int phydata;
u16 timeoutms = 100;
err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7588, 0x2);
if (err < 0)
return err;
err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7589, 0x71d0);
if (err < 0)
return err;
err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7587, 0x3);
if (err < 0)
return err;
while(--timeoutms)
{
phydata = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x7587);
if((phydata & 0x01) == 0)
break;
mdelay(10);
}
phydata = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x75F3);
phydata &= ~BIT_0;
err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75F3, phydata);
if (err < 0)
return err;
phydata = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x697A);
phydata &= (~(BIT_0 | BIT_1 | BIT_2 | BIT_3 | BIT_4 | BIT_5));
phydata |= 2;
phydata |=0x8000;
err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x697A, phydata);
if (err < 0)
return err;
phydata = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x697A);
Rtl8226b_is_link(phydev);
if (phydev->link)
{
phydata = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, 0x0);
phydata |= BIT_15;
err = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, 0x0, phydata);
if (err < 0)
return err;
while(--timeoutms)
{
phydata = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, 0x0);
if (!(phydata & BIT_15))
break;
mdelay(10);
}
err = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, 0x0, phydata);
if (err < 0)
return err;
}
else
{
phydata = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa400);
phydata |= BIT_14;
err = phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xa400, phydata);
if (err < 0)
return err;
while(--timeoutms)
{
phydata = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xA434);
if (phydata & BIT_2)
break;
mdelay(10);
}
phydata = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa400);
phydata &= ~BIT_14;
err = phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xa400, phydata);
if (err < 0)
return err;
}
return 0;
}
static int rtl8221d_probe(struct phy_device *phydev)
{
printk("rtl8221d probe");
return 0;
}
static struct phy_driver aqr_driver[] = {
{
PHY_ID_MATCH_MODEL(PHY_ID_RTL8221D),
.name = "Rtl 8221D",
.features = PHY_GBIT_FEATURES,
.probe = rtl8221d_probe,
.config_init = rtl8221d_config_init,
.config_aneg = rtl8221d_config_aneg,
.read_status = rtl8221d_read_status,
},
};
module_phy_driver(aqr_driver);
static struct mdio_device_id __maybe_unused rtl_tbl[] = {
{ PHY_ID_MATCH_MODEL(PHY_ID_RTL8221D) },
{ }
};
MODULE_DEVICE_TABLE(mdio, rtl_tbl);
MODULE_DESCRIPTION("rtl8221d PHY driver");
MODULE_AUTHOR("haungyunxiang huangyunxiang@cigtech.com>");
MODULE_LICENSE("GPL v2");

View File

@@ -79,6 +79,20 @@ define Device/sonicfi_rap750e_h
endef endef
TARGET_DEVICES += sonicfi_rap750e_h TARGET_DEVICES += sonicfi_rap750e_h
define Device/sonicfi_rap750e_s
DEVICE_TITLE := SONICFI RAP750E-S
DEVICE_DTS := ipq5332-sonicfi-rap750e-s
DEVICE_DTS_DIR := ../dts
DEVICE_DTS_CONFIG := config@mi01.3-c2
SUPPORTED_DEVICES := sonicfi,rap750e-s
IMAGES := sysupgrade.tar nand-factory.bin nand-factory.ubi
IMAGE/sysupgrade.tar := sysupgrade-tar | append-metadata
IMAGE/nand-factory.bin := append-ubi | qsdk-ipq-factory-nand
IMAGE/nand-factory.ubi := append-ubi
DEVICE_PACKAGES := ath12k-wifi-sonicfi-rap750e-s ath12k-firmware-ipq5332-peb -ath12k-firmware-qcn92xx
endef
TARGET_DEVICES += sonicfi_rap750e_s
define Device/sonicfi_rap750w_311a define Device/sonicfi_rap750w_311a
DEVICE_TITLE := SONICFI RAP750W-311A DEVICE_TITLE := SONICFI RAP750W-311A
DEVICE_DTS := ipq5332-sonicfi-rap750w-311a DEVICE_DTS := ipq5332-sonicfi-rap750w-311a
@@ -134,3 +148,15 @@ define Device/zyxel_nwa130be
DEVICE_PACKAGES := ath12k-wifi-zyxel-nwa130be ath12k-firmware-qcn92xx ath12k-firmware-ipq5332 DEVICE_PACKAGES := ath12k-wifi-zyxel-nwa130be ath12k-firmware-qcn92xx ath12k-firmware-ipq5332
endef endef
TARGET_DEVICES += zyxel_nwa130be TARGET_DEVICES += zyxel_nwa130be
define Device/cig_wf672
DEVICE_TITLE := CIG WF672
DEVICE_DTS := ipq5332-cig-wf672
DEVICE_DTS_DIR := ../dts
DEVICE_DTS_CONFIG := config@mi01.6
IMAGES := sysupgrade.tar mmc-factory.bin
IMAGE/mmc-factory.bin := append-ubi | qsdk-ipq-factory-mmc
IMAGE/sysupgrade.tar := sysupgrade-tar | append-metadata
DEVICE_PACKAGES := ath12k-wifi-cig-wf672 ath12k-firmware-ipq5332 ath12k-firmware-qcn92xx
endef
TARGET_DEVICES += cig_wf672

View File

@@ -0,0 +1,63 @@
--- a/drivers/input/misc/Kconfig 2025-04-22 14:35:28.228629072 +0800
+++ b/drivers/input/misc/Kconfig 2025-04-22 14:42:29.630935581 +0800
@@ -929,4 +929,5 @@
To compile this driver as a module, choose M here: the
module will be called stpmic1_onkey.
+source "drivers/input/misc/lsm303agr/Kconfig"
endif
--- a/drivers/input/misc/Makefile 2025-04-22 14:35:28.228629072 +0800
+++ b/drivers/input/misc/Makefile 2025-04-22 14:41:23.840267623 +0800
@@ -89,3 +89,4 @@
obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o
+obj-$(CONFIG_INPUT_LSM303AGR) += lsm303agr/
--- a/drivers/net/phy/Kconfig 2025-04-22 14:48:04.858191804 +0800
+++ b/drivers/net/phy/Kconfig 2025-04-22 10:17:06.822705335 +0800
@@ -99,6 +99,9 @@
tristate "Lantiq XWAY Tantos (PSB6970) Ethernet switch"
select SWCONFIG
+config RTL8221D_PHY
+ tristate "Driver for Realtek RTL8221D phy"
+
config RTL8306_PHY
tristate "Driver for Realtek RTL8306S switches"
select SWCONFIG
--- a/drivers/net/phy/Makefile 2025-04-22 14:48:18.254372527 +0800
+++ b/drivers/net/phy/Makefile 2025-04-22 10:17:10.546732447 +0800
@@ -32,6 +32,7 @@
obj-$(CONFIG_SWCONFIG_B53) += b53/
obj-$(CONFIG_IP17XX_PHY) += ip17xx.o
obj-$(CONFIG_PSB6970_PHY) += psb6970.o
+obj-$(CONFIG_RTL8221D_PHY) += rtl8221d.o
obj-$(CONFIG_RTL8306_PHY) += rtl8306.o
obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi.o
obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o
--- a/drivers/iio/pressure/Kconfig 2025-05-13 15:16:05.019840003 +0800
+++ b/drivers/iio/pressure/Kconfig 2025-05-13 15:17:45.032040654 +0800
@@ -266,4 +266,11 @@
tristate
select REGMAP_SPI
+config ILPS22QS
+ tristate "ILPS22QS pressure support"
+ help
+ Say Y to enable support ILPS22QS
+
+ To compile this driver as a module, choose M here: the
+ module will be called ILPS22QS.
endmenu
--- a/drivers/iio/pressure/Makefile 2025-05-13 15:17:58.049195788 +0800
+++ b/drivers/iio/pressure/Makefile 2025-05-13 15:19:07.205016058 +0800
@@ -31,6 +31,8 @@
obj-$(CONFIG_ZPA2326) += zpa2326.o
obj-$(CONFIG_ZPA2326_I2C) += zpa2326_i2c.o
obj-$(CONFIG_ZPA2326_SPI) += zpa2326_spi.o
+obj-$(CONFIG_ILPS22QS) += st_ilps22qs.o
+st_ilps22qs-objs := st_ilps22qs_i2c.o st_ilps22qs_core.o
obj-$(CONFIG_IIO_ST_PRESS_I2C) += st_pressure_i2c.o
obj-$(CONFIG_IIO_ST_PRESS_SPI) += st_pressure_spi.o

View File

@@ -397,7 +397,7 @@ export function info(name) {
mode: data.mode, mode: data.mode,
channel: format_channel(data.wiphy_freq), channel: format_channel(data.wiphy_freq),
freq: format_frequency(data.wiphy_freq), freq: format_frequency(data.wiphy_freq),
htmode: data.radio.htmode, htmode: data?.radio?.htmode,
center_freq1: format_channel(data.center_freq1) || 'unknown', center_freq1: format_channel(data.center_freq1) || 'unknown',
center_freq2: format_channel(data.center_freq2) || 'unknown', center_freq2: format_channel(data.center_freq2) || 'unknown',
txpower: data.wiphy_tx_power_level / 100, txpower: data.wiphy_tx_power_level / 100,

View File

@@ -702,3 +702,44 @@ define KernelPackage/llcc_perfmon/description
endef endef
$(eval $(call KernelPackage,llcc_perfmon)) $(eval $(call KernelPackage,llcc_perfmon))
define KernelPackage/input-lsm303agr
SUBMENU:=$(OTHER_MENU)
TITLE:=LSM303AGR Driver
DEPENDS+=@TARGET_ipq53xx
KCONFIG:=CONFIG_INPUT_LSM303AGR=y
endef
define KernelPackage/input-lsm303agr/description
lsm303agr driver support
endef
$(eval $(call KernelPackage,input-lsm303agr))
define KernelPackage/rtl8221d-phy
SUBMENU:=$(OTHER_MENU)
TITLE:=RTL8221d PHY Driver
DEPENDS+=@TARGET_ipq53xx
KCONFIG:=CONFIG_RTL8221D_PHY=y
endef
define KernelPackage/rtl8221d-phy/description
RTL8221d PHY driver support
endef
$(eval $(call KernelPackage,rtl8221d-phy))
define KernelPackage/iio-ilps22qs
SUBMENU:=$(IIO_MENU)
TITLE:= pressure sensors ilps22qs Driver
DEPENDS+=@TARGET_ipq53xx +kmod-iio-core +kmod-industrialio-triggered-buffer
KCONFIG:=CONFIG_ILPS22QS
FILES:=$(LINUX_DIR)/drivers/iio/pressure/st_ilps22qs.ko
AUTOLOAD:=$(call AutoLoad,80,st_ilps22qs)
endef
define KernelPackage/iio-ilps22qs/description
pressure sensors ilps22qs driver support
endef
$(eval $(call KernelPackage,iio-ilps22qs))

View File

@@ -25,6 +25,10 @@ cig,wf660a)
mmc_dev=$(echo $(find_mmc_part "0:ETHPHYFW") | sed 's/^.\{5\}//') mmc_dev=$(echo $(find_mmc_part "0:ETHPHYFW") | sed 's/^.\{5\}//')
[ -n "$mmc_dev" ] && mount -t ext4 /dev/$mmc_dev /certificates [ -n "$mmc_dev" ] && mount -t ext4 /dev/$mmc_dev /certificates
;; ;;
cig,wf672)
mmc_dev=$(echo $(find_mmc_part "cert") | sed 's/^.\{5\}//')
[ -n "$mmc_dev" ] && mount -t ext4 /dev/$mmc_dev /certificates
;;
sonicfi,rap7110c-341x) sonicfi,rap7110c-341x)
mmc_dev=$(echo $(find_mmc_part "certificates") | sed 's/^.\{5\}//') mmc_dev=$(echo $(find_mmc_part "certificates") | sed 's/^.\{5\}//')
[ -n "$mmc_dev" ] && mount -t squashfs /dev/$mmc_dev /certificates [ -n "$mmc_dev" ] && mount -t squashfs /dev/$mmc_dev /certificates
@@ -82,6 +86,8 @@ cig,wf189|\
cig,wf189w|\ cig,wf189w|\
cig,wf189h|\ cig,wf189h|\
cig,wf186h|\ cig,wf186h|\
cig,wf196|\
cig,wf188n|\
yuncore,ax840|\ yuncore,ax840|\
yuncore,fap655) yuncore,fap655)
PART_NAME=rootfs_1 PART_NAME=rootfs_1

View File

@@ -4,10 +4,10 @@ PKG_NAME:=ucentral-schema
PKG_RELEASE:=1 PKG_RELEASE:=1
PKG_SOURCE_URL=https://github.com/Telecominfraproject/wlan-ucentral-schema.git PKG_SOURCE_URL=https://github.com/Telecominfraproject/wlan-ucentral-schema.git
PKG_MIRROR_HASH:=cbb6508faa5e0b640e1990a806383f9f13fb5da75f38114f4f32e9c14b9845f1 PKG_MIRROR_HASH:=ee5d5073bd9ae88590e419f94eb6c59f04a2fc0c3117be435bcb885e0ea28bf1
PKG_SOURCE_PROTO:=git PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2025-01-27 PKG_SOURCE_DATE:=2025-01-27
PKG_SOURCE_VERSION:=9710867e1a2c775fa424fd7780ba6132eaa6fd9c PKG_SOURCE_VERSION:=b4cfdc6a1caa279ae8c6c42b6932620fb2aed9c1
PKG_MAINTAINER:=John Crispin <john@phrozen.org> PKG_MAINTAINER:=John Crispin <john@phrozen.org>
PKG_LICENSE:=BSD-3-Clause PKG_LICENSE:=BSD-3-Clause

23
profiles/cig_wf672.yml Normal file
View File

@@ -0,0 +1,23 @@
---
profile: cig_wf672
target: ipq53xx
subtarget: generic
description: Build image for the CIG WF672
image: bin/targets/ipq53xx/generic/openwrt-ipq53xx-cig_wf672-squashfs-sysupgrade.tar
feeds:
- name: qca
path: ../../feeds/qca-wifi-7
include:
- ucentral-ap
packages:
- ipq53xx
- ftm
- qca-ssdk-shell
- iperf3
- sysstat
- kmod-cig-wifi-mode-sw
- kmod-input-lsm303agr
- kmod-rtl8221d-phy
- kmod-gpio-pca953x
- kmod-hwmon-tmp103
- kmod-iio-ilps22qs

View File

@@ -44,6 +44,7 @@ packages:
- morse-regdb - morse-regdb
include: include:
- ucentral-ap - ucentral-ap
- hostapd
diffconfig: | diffconfig: |
# CONFIG_PACKAGE_kmod-nft-offload is not set # CONFIG_PACKAGE_kmod-nft-offload is not set
# CONFIG_PACKAGE_procd-ujail is not set # CONFIG_PACKAGE_procd-ujail is not set

16
profiles/sonicfi_rap750e-s.yml Executable file
View File

@@ -0,0 +1,16 @@
---
profile: sonicfi_rap750e_s
target: ipq53xx
subtarget: generic
description: Build image for the SONICFI RAP750E-S
image: bin/targets/ipq53xx/generic/openwrt-ipq53xx-sonicfi_rap750e_s-squashfs-sysupgrade.tar
feeds:
- name: qca
path: ../../feeds/qca-wifi-7
include:
- ucentral-ap
packages:
- ipq53xx
- qca-ssdk-shell
diffconfig: |
CONFIG_KERNEL_IPQ_MEM_PROFILE=512