Compare commits

...

21 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
800246@emplustech.com
a2e1ffe089 mediatek: Swiitch LAN and WAN port for EMPLUS WAP588M
Signed-off-by: 800246@emplustech.com <cp.chang@emplustech.com>
2025-05-19 06:11:46 +02:00
polun
911f8eaa4c qca-wifi-7: Add Zyxel NWA130BE model
Signed-off-by: YenLin Pan <YenLin.Pan@zyxel.com.tw>
2025-05-19 06:11:20 +02:00
Tanya Singh
590ee6d514 mediatek: Update ethernet driver to support PHY AN8801 on Edgecore EAP111
Fixes: WIFI-14576
Signed-off-by: Tanya Singh <tanya_singh@accton.com>
2025-05-19 06:10:35 +02:00
Ken
5054a71062 qca-wifi-7: WF189 Save crash log into pstore
Fixes: WIFI-14582
Signed-off-by: Ken <xshi@actiontec.com>
2025-05-19 06:09:53 +02:00
John Crispin
d69c1c3176 ucentral-schema: update to latest HEAD
9710867 (HEAD -> main, origin/main, origin/HEAD) make the MTU configurable on GRE tunnels
4dd0904 SSH IdleTimeout can be configured from JSON config
6faaa1f HaLow: Extend ucentral schema & state for HaLow

Signed-off-by: John Crispin <john@phrozen.org>
2025-05-19 06:09:01 +02:00
60 changed files with 6403 additions and 272 deletions

View File

@@ -21,7 +21,7 @@ jobs:
strategy:
fail-fast: false
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' ]
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:
- uses: actions/checkout@v3

View File

@@ -169,7 +169,8 @@
compatible = "mediatek,eth-mac";
reg = <0>;
phy-mode = "sgmii";
phy-handle = <&phy1>; // add phy handler
phy-handle = <&phy30>;
phy-handle2 = <&phy1>;
mtd-mac-address = <&factory 0x24>;
};
@@ -181,9 +182,9 @@
mtd-mac-address = <&factory 0x2a>;
};
mdio: mdio-bus {
#address-cells = <1>;
#size-cells = <0>;
mdio: mdio-bus {
#address-cells = <1>;
#size-cells = <0>;
phy0: ethernet-phy@0 {
compatible = "ethernet-phy-id03a2.9461";
@@ -193,6 +194,16 @@
nvmem-cell-names = "phy-cal-data";
};
phy30: ethernet-phy@30 { // AN8801SB
compatible = "ethernet-phy-idc0ff.0421";
reg = <30>; //0x1e
phy-mode = "sgmii";
full-duplex;
pause;
airoha,surge = <1>;
airoha,polarity = <2>;
};
phy1: ethernet-phy@1 {
compatible = "ethernet-phy-id03a2.9471";
reg = <24>; // set phy address to 0x18
@@ -200,9 +211,8 @@
reset-assert-us = <600>;
reset-deassert-us = <20000>;
phy-mode = "sgmii";
};
};
};
};
};
&hnat {

View File

@@ -113,7 +113,6 @@ static const struct AIR_LED_CFG_T led_cfg_dlt[MAX_LED_SIZE] = {
/* LED2 */
{LED_ENABLE, AIR_LED_GPIO9, AIR_ACTIVE_LOW, AIR_LED2_ON, AIR_LED2_BLK},
};
static const u16 led_blink_cfg_dlt = AIR_LED_BLK_DUR_64M;
/* RGMII delay */
static const u8 rxdelay_force = FALSE;
@@ -140,7 +139,6 @@ static int __air_buckpbus_reg_write(struct phy_device *phydev, u32 addr,
err |= mbus->write(mbus, phy_addr, 0x13, (u16)(data >> 16));
err |= mbus->write(mbus, phy_addr, 0x14, (u16)(data & 0xffff));
err |= mbus->write(mbus, phy_addr, 0x1F, 0);
return err;
}
@@ -167,6 +165,41 @@ static u32 __air_buckpbus_reg_read(struct phy_device *phydev, u32 addr)
return data;
}
static u32 __air_buckpbus_reg_modify(struct phy_device *phydev, u32 addr,
u32 mask, u32 set)
{
int err = 0;
u32 data_h, data_l, data_old, data_new;
int phy_addr = phydev_phy_addr(phydev);
struct mii_bus *mbus = phydev_mdiobus(phydev);
err = mbus->write(mbus, phy_addr, 0x1F, 4);
err |= mbus->write(mbus, phy_addr, 0x10, 0);
err |= mbus->write(mbus, phy_addr, 0x15, (u16)(addr >> 16));
err |= mbus->write(mbus, phy_addr, 0x16, (u16)(addr & 0xffff));
data_h = mbus->read(mbus, phy_addr, 0x17);
data_l = mbus->read(mbus, phy_addr, 0x18);
if (err < 0) {
mbus->write(mbus, phy_addr, 0x1F, 0);
return INVALID_DATA;
}
data_old = ((data_h & 0xffff) << 16) | (data_l & 0xffff);
data_new = (data_old & ~mask) | set;
if (data_new == data_old) {
mbus->write(mbus, phy_addr, 0x1F, 0);
return 0;
}
err |= mbus->write(mbus, phy_addr, 0x11, (u16)(addr >> 16));
err |= mbus->write(mbus, phy_addr, 0x12, (u16)(addr & 0xffff));
err |= mbus->write(mbus, phy_addr, 0x13, (u16)(data_new >> 16));
err |= mbus->write(mbus, phy_addr, 0x14, (u16)(data_new & 0xffff));
err |= mbus->write(mbus, phy_addr, 0x1F, 0);
return err;
}
static int air_buckpbus_reg_write(struct phy_device *phydev, u32 addr, u32 data)
{
int err = 0;
@@ -189,82 +222,18 @@ static u32 air_buckpbus_reg_read(struct phy_device *phydev, u32 addr)
return data;
}
static int __an8801_cl45_write(struct phy_device *phydev, int devad, u16 reg,
u16 val)
{
u32 addr = (AN8801_EPHY_ADDR | AN8801_CL22 | (devad << 18) |
(reg << 2));
return __air_buckpbus_reg_write(phydev, addr, val);
}
static int __an8801_cl45_read(struct phy_device *phydev, int devad, u16 reg)
{
u32 addr = (AN8801_EPHY_ADDR | AN8801_CL22 | (devad << 18) |
(reg << 2));
return __air_buckpbus_reg_read(phydev, addr);
}
int __an8801_modify_cl45_changed(struct phy_device *phydev, int devad, u32 regnum,
u16 mask, u16 set)
{
int new, ret;
ret = __an8801_cl45_read(phydev, devad, regnum);
if (ret < 0)
return ret;
new = (ret & ~mask) | set;
if (new == ret)
return 0;
ret = __an8801_cl45_write(phydev, devad, regnum, new);
return ret < 0 ? ret : 1;
}
static int an8801_modify_cl45_changed(struct phy_device *phydev, int devad,
u32 regnum, u16 mask, u16 set)
static int air_buckpbus_reg_modify(struct phy_device *phydev, u32 addr,
u32 mask, u32 set)
{
int err = 0;
mdiobus_lock(phydev);
err = __an8801_modify_cl45_changed(phydev, devad, regnum, mask, set);
err = __air_buckpbus_reg_modify(phydev, addr, mask, set);
mdiobus_unlock(phydev);
return err;
}
static int an8801_cl45_write(struct phy_device *phydev, int devad, u16 reg,
u16 val)
{
int err = 0;
mdiobus_lock(phydev);
err = __an8801_cl45_write(phydev, devad, reg, val);
mdiobus_unlock(phydev);
return err;
}
static int an8801_cl45_read(struct phy_device *phydev, int devad, u16 reg,
u16 *read_data)
{
int data = 0;
mdiobus_lock(phydev);
data = __an8801_cl45_read(phydev, devad, reg);
mdiobus_unlock(phydev);
if (data == INVALID_DATA)
return -EINVAL;
*read_data = data;
return 0;
}
static int air_sw_reset(struct phy_device *phydev)
{
u32 reg_value;
@@ -298,50 +267,36 @@ static int an8801_led_set_usr_def(struct phy_device *phydev, u8 entity,
on_evt |= LED_ON_EN;
err = an8801_cl45_write(phydev, 0x1f, LED_ON_CTRL(entity), on_evt);
err = phy_write_mmd(phydev, 0x1f, LED_ON_CTRL(entity), on_evt);
if (err)
return -1;
return an8801_cl45_write(phydev, 0x1f, LED_BLK_CTRL(entity), blk_evt);
return phy_write_mmd(phydev, 0x1f, LED_BLK_CTRL(entity), blk_evt);
}
static int an8801_led_set_mode(struct phy_device *phydev, u8 mode)
{
int err;
u16 data;
err = an8801_cl45_read(phydev, 0x1f, LED_BCR, &data);
if (err)
return -1;
switch (mode) {
case AIR_LED_MODE_DISABLE:
data &= ~LED_BCR_EXT_CTRL;
data &= ~LED_BCR_MODE_MASK;
data |= LED_BCR_MODE_DISABLE;
break;
return phy_modify_mmd(phydev, 0x1f, LED_BCR,
(LED_BCR_EXT_CTRL | LED_BCR_CLK_EN),
0x0);
case AIR_LED_MODE_USER_DEFINE:
data |= (LED_BCR_EXT_CTRL | LED_BCR_CLK_EN);
return phy_modify_mmd(phydev, 0x1f, LED_BCR,
(LED_BCR_EXT_CTRL | LED_BCR_CLK_EN),
(LED_BCR_EXT_CTRL | LED_BCR_CLK_EN));
default:
break;
}
return an8801_cl45_write(phydev, 0x1f, LED_BCR, data);
dev_err(phydev_dev(phydev),
"LED mode %d is not supported\n", mode);
return -EINVAL;
}
static int an8801_led_set_state(struct phy_device *phydev, u8 entity, u8 state)
{
u16 data;
int err;
err = an8801_cl45_read(phydev, 0x1f, LED_ON_CTRL(entity), &data);
if (err)
return err;
if (state)
data |= LED_ON_EN;
else
data &= ~LED_ON_EN;
return an8801_cl45_write(phydev, 0x1f, LED_ON_CTRL(entity), data);
return phy_modify_mmd(phydev, 0x1f, LED_ON_CTRL(entity), LED_ON_EN,
(state) ? LED_ON_EN : 0x0);
}
static int an8801_led_init(struct phy_device *phydev)
@@ -352,12 +307,12 @@ static int an8801_led_init(struct phy_device *phydev)
u32 data;
u16 led_blink_cfg = priv->led_blink_cfg;
ret = an8801_cl45_write(phydev, 0x1f, LED_BLK_DUR,
ret = phy_write_mmd(phydev, 0x1f, LED_BLK_DUR,
LED_BLINK_DURATION(led_blink_cfg));
if (ret < 0)
return ret;
ret = an8801_cl45_write(phydev, 0x1f, LED_ON_DUR,
ret = phy_write_mmd(phydev, 0x1f, LED_ON_DUR,
(LED_BLINK_DURATION(led_blink_cfg) >> 1));
if (ret < 0)
return ret;
@@ -406,6 +361,56 @@ static int an8801_led_init(struct phy_device *phydev)
return 0;
}
static int an8801_ack_interrupt(struct phy_device *phydev)
{
u32 reg_val = 0;
air_buckpbus_reg_write(phydev, 0x10285404, 0x102);
reg_val = air_buckpbus_reg_read(phydev, 0x10285400);
air_buckpbus_reg_write(phydev, 0x10285400, 0x0);
air_buckpbus_reg_write(phydev, 0x10285400, reg_val | 0x10);
air_buckpbus_reg_write(phydev, 0x10285404, 0x12);
air_buckpbus_reg_write(phydev, 0x10285704, 0x1f);
return 0;
}
static int an8801_config_intr(struct phy_device *phydev)
{
if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
air_buckpbus_reg_write(phydev, 0x1000007c, BIT(AIR_INTERRUPT_GPIO) << 16);
air_buckpbus_reg_modify(phydev, 0x10285700, 0x1, 0x1);
} else {
air_buckpbus_reg_write(phydev, 0x1000007c, 0x0);
air_buckpbus_reg_modify(phydev, 0x10285700, 0x1, 0x0);
}
an8801_ack_interrupt(phydev);
return 0;
}
static int an8801_did_interrupt(struct phy_device *phydev)
{
u32 reg_val = 0;
reg_val = air_buckpbus_reg_read(phydev, 0x10285704);
if (reg_val & 0x11)
return 1;
return 0;
}
#if (KERNEL_VERSION(5, 11, 0) < LINUX_VERSION_CODE)
static irqreturn_t an8801_handle_interrupt(struct phy_device *phydev)
{
if (!an8801_did_interrupt(phydev))
return IRQ_NONE;
an8801_ack_interrupt(phydev);
phy_trigger_machine(phydev);
return IRQ_HANDLED;
}
#endif
static int findClosestNumber(const u16 *arr, u16 size, u16 target)
{
int left = 0, right = size - 1;
@@ -431,77 +436,77 @@ static int findClosestNumber(const u16 *arr, u16 size, u16 target)
static int an8801sb_i2mpb_config(struct phy_device *phydev)
{
int ret = 0;
u16 cl45_value = 0, temp_cl45 = 0, set = 0;
u16 cl45_value = 0, temp_cl45 = 0;
u16 mask = 0;
ret = an8801_cl45_read(phydev, MMD_DEV_VSPEC1, 0x12, &cl45_value);
cl45_value = phy_read_mmd(phydev, MMD_DEV_VSPEC1, 0x12);
dev_dbg(phydev_dev(phydev), "%s:%d cl45_value 0x%x!\n", __func__, __LINE__, cl45_value);
cl45_value = (cl45_value & GENMASK(15, 10)) + (6 << 10);
ret = an8801_modify_cl45_changed(phydev, MMD_DEV_VSPEC1, 0x12, GENMASK(15, 10), cl45_value);
ret = phy_modify_mmd(phydev, MMD_DEV_VSPEC1, 0x12, GENMASK(15, 10), cl45_value);
if (ret < 0)
return ret;
ret = an8801_cl45_read(phydev, MMD_DEV_VSPEC1, 0x16, &temp_cl45);
temp_cl45 = phy_read_mmd(phydev, MMD_DEV_VSPEC1, 0x16);
dev_dbg(phydev_dev(phydev), "%s:%d cl45_value 0x%x!\n", __func__, __LINE__, temp_cl45);
mask = GENMASK(15, 10) | GENMASK(5, 0);
cl45_value = (temp_cl45 & GENMASK(15, 10)) + (9 << 10);
cl45_value = ((temp_cl45 & GENMASK(5, 0)) + 6) | cl45_value;
ret = an8801_modify_cl45_changed(phydev, MMD_DEV_VSPEC1, 0x16, mask, cl45_value);
ret = phy_modify_mmd(phydev, MMD_DEV_VSPEC1, 0x16, mask, cl45_value);
if (ret < 0)
return ret;
ret = an8801_cl45_read(phydev, MMD_DEV_VSPEC1, 0x17, &cl45_value);
cl45_value = phy_read_mmd(phydev, MMD_DEV_VSPEC1, 0x17);
dev_dbg(phydev_dev(phydev), "%s:%d cl45_value 0x%x!\n", __func__, __LINE__, cl45_value);
cl45_value = (cl45_value & GENMASK(13, 8)) + (6 << 8);
ret = an8801_modify_cl45_changed(phydev, MMD_DEV_VSPEC1, 0x17, GENMASK(13, 8), cl45_value);
ret = phy_modify_mmd(phydev, MMD_DEV_VSPEC1, 0x17, GENMASK(13, 8), cl45_value);
if (ret < 0)
return ret;
ret = an8801_cl45_read(phydev, MMD_DEV_VSPEC1, 0x18, &temp_cl45);
temp_cl45 = phy_read_mmd(phydev, MMD_DEV_VSPEC1, 0x18);
dev_dbg(phydev_dev(phydev), "%s:%d cl45_value 0x%x!\n", __func__, __LINE__, temp_cl45);
mask = GENMASK(13, 8) | GENMASK(5, 0);
cl45_value = (temp_cl45 & GENMASK(13, 8)) + (9 << 8);
cl45_value = ((temp_cl45 & GENMASK(5, 0)) + 6) | cl45_value;
ret = an8801_modify_cl45_changed(phydev, MMD_DEV_VSPEC1, 0x18, mask, cl45_value);
ret = phy_modify_mmd(phydev, MMD_DEV_VSPEC1, 0x18, mask, cl45_value);
if (ret < 0)
return ret;
ret = an8801_cl45_read(phydev, MMD_DEV_VSPEC1, 0x19, &cl45_value);
cl45_value = phy_read_mmd(phydev, MMD_DEV_VSPEC1, 0x19);
dev_dbg(phydev_dev(phydev), "%s:%d cl45_value 0x%x!\n", __func__, __LINE__, cl45_value);
cl45_value = (cl45_value & GENMASK(13, 8)) + (6 << 8);
ret = an8801_modify_cl45_changed(phydev, MMD_DEV_VSPEC1, 0x19, GENMASK(13, 8), cl45_value);
ret = phy_modify_mmd(phydev, MMD_DEV_VSPEC1, 0x19, GENMASK(13, 8), cl45_value);
if (ret < 0)
return ret;
ret = an8801_cl45_read(phydev, MMD_DEV_VSPEC1, 0x20, &cl45_value);
cl45_value = phy_read_mmd(phydev, MMD_DEV_VSPEC1, 0x20);
dev_dbg(phydev_dev(phydev), "%s:%d cl45_value 0x%x!\n", __func__, __LINE__, cl45_value);
cl45_value = (cl45_value & GENMASK(5, 0)) + 6;
ret = an8801_modify_cl45_changed(phydev, MMD_DEV_VSPEC1, 0x20, GENMASK(5, 0), cl45_value);
ret = phy_modify_mmd(phydev, MMD_DEV_VSPEC1, 0x20, GENMASK(5, 0), cl45_value);
if (ret < 0)
return ret;
ret = an8801_cl45_read(phydev, MMD_DEV_VSPEC1, 0x21, &cl45_value);
cl45_value = phy_read_mmd(phydev, MMD_DEV_VSPEC1, 0x21);
dev_dbg(phydev_dev(phydev), "%s:%d cl45_value 0x%x!\n", __func__, __LINE__, cl45_value);
cl45_value = (cl45_value & GENMASK(13, 8)) + (6 << 8);
ret = an8801_modify_cl45_changed(phydev, MMD_DEV_VSPEC1, 0x21, GENMASK(13, 8), cl45_value);
ret = phy_modify_mmd(phydev, MMD_DEV_VSPEC1, 0x21, GENMASK(13, 8), cl45_value);
if (ret < 0)
return ret;
ret = an8801_cl45_read(phydev, MMD_DEV_VSPEC1, 0x22, &cl45_value);
cl45_value = phy_read_mmd(phydev, MMD_DEV_VSPEC1, 0x22);
dev_dbg(phydev_dev(phydev), "%s:%d cl45_value 0x%x!\n", __func__, __LINE__, cl45_value);
cl45_value = (cl45_value & GENMASK(5, 0)) + 6;
ret = an8801_modify_cl45_changed(phydev, MMD_DEV_VSPEC1, 0x22, GENMASK(5, 0), cl45_value);
ret = phy_modify_mmd(phydev, MMD_DEV_VSPEC1, 0x22, GENMASK(5, 0), cl45_value);
if (ret < 0)
return ret;
ret = an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x23, 0x883);
ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x24, 0x883);
ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x25, 0x883);
ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x26, 0x883);
ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x0, 0x100);
ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x1, 0x1bc);
ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x2, 0x1d0);
ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x3, 0x186);
ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x4, 0x202);
ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x5, 0x20e);
ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x6, 0x300);
ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x7, 0x3c0);
ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x8, 0x3d0);
ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x9, 0x317);
ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0xa, 0x206);
ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0xb, 0xe);
ret = phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x23, 0x883);
ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x24, 0x883);
ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x25, 0x883);
ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x26, 0x883);
ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x0, 0x100);
ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x1, 0x1bc);
ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x2, 0x1d0);
ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x3, 0x186);
ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x4, 0x202);
ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x5, 0x20e);
ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x6, 0x300);
ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x7, 0x3c0);
ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x8, 0x3d0);
ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x9, 0x317);
ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0xa, 0x206);
ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0xb, 0xe);
if (ret < 0)
return ret;
@@ -510,14 +515,14 @@ static int an8801sb_i2mpb_config(struct phy_device *phydev)
}
void update_r50_value(struct phy_device *phydev,
u16 *cl45_value, int pos1, int pos2)
u16 *cl45_value, int pos1, int pos2)
{
*cl45_value &= ~(0x007f << 8);
*cl45_value |= ((r50ohm_table[pos1]) & 0x007f) << 8;
*cl45_value &= ~(0x007f);
*cl45_value |= (r50ohm_table[pos2]) & 0x007f;
dev_dbg(phydev_dev(phydev), "Read: r50ohm_tx_1=%d r50ohm_tx_2=%d\n",
r50ohm_table[pos1], r50ohm_table[pos2]);
r50ohm_table[pos1], r50ohm_table[pos2]);
}
int calculate_position(int pos, int shift, int table_size)
@@ -529,7 +534,7 @@ int calculate_position(int pos, int shift, int table_size)
}
int process_r50(struct phy_device *phydev, int reg,
u16 *cl45_value, u16 *r50ohm_tx_a, u16 *r50ohm_tx_b)
u16 *cl45_value, u16 *r50ohm_tx_a, u16 *r50ohm_tx_b)
{
int pos1 = findClosestNumber(r50ohm_table, r50ohm_table_size, *r50ohm_tx_a);
int pos2 = findClosestNumber(r50ohm_table, r50ohm_table_size, *r50ohm_tx_b);
@@ -539,7 +544,7 @@ int process_r50(struct phy_device *phydev, int reg,
pos2 = calculate_position(pos2, R50_SHIFT, r50ohm_table_size);
update_r50_value(phydev, cl45_value, pos1, pos2);
return an8801_cl45_write(phydev, 0x1e, reg, *cl45_value);
return phy_write_mmd(phydev, 0x1e, reg, *cl45_value);
}
return 0;
}
@@ -558,10 +563,10 @@ static int an8801r_of_init(struct phy_device *phydev)
return -1;
}
if (val < AIR_RGMII_DELAY_NOSTEP ||
val > AIR_RGMII_DELAY_STEP_7) {
val > AIR_RGMII_DELAY_STEP_7) {
dev_err(phydev_dev(phydev),
"airoha,rxclk-delay value %u out of range.",
val);
"airoha,rxclk-delay value %u out of range.",
val);
return -1;
}
priv->rxdelay_force = TRUE;
@@ -574,14 +579,14 @@ static int an8801r_of_init(struct phy_device *phydev)
if (of_property_read_u32(of_node, "airoha,txclk-delay",
&val) != 0) {
dev_err(phydev_dev(phydev),
"airoha,txclk-delay value is invalid.");
"airoha,txclk-delay value is invalid.");
return -1;
}
if (val < AIR_RGMII_DELAY_NOSTEP ||
val > AIR_RGMII_DELAY_STEP_7) {
val > AIR_RGMII_DELAY_STEP_7) {
dev_err(phydev_dev(phydev),
"airoha,txclk-delay value %u out of range.",
val);
"airoha,txclk-delay value %u out of range.",
val);
return -1;
}
priv->txdelay_force = TRUE;
@@ -603,10 +608,10 @@ static int an8801sb_of_init(struct phy_device *phydev)
return -1;
}
if (val < AIR_POL_TX_NOR_RX_REV ||
val > AIR_POL_TX_REV_RX_NOR) {
val > AIR_POL_TX_REV_RX_NOR) {
dev_err(phydev_dev(phydev),
"airoha,polarity value %u out of range.",
val);
"airoha,polarity value %u out of range.",
val);
return -1;
}
priv->pol = val;
@@ -615,15 +620,15 @@ static int an8801sb_of_init(struct phy_device *phydev)
if (of_find_property(of_node, "airoha,surge", NULL)) {
if (of_property_read_u32(of_node, "airoha,surge",
&val) != 0) {
&val) != 0) {
dev_err(phydev_dev(phydev), "airoha,surge value is invalid.");
return -1;
}
if (val < AIR_SURGE_0R ||
val > AIR_SURGE_5R) {
dev_err(phydev_dev(phydev),
"airoha,surge value %u out of range.",
val);
"airoha,surge value %u out of range.",
val);
return -1;
}
priv->surge = val;
@@ -693,23 +698,19 @@ int an8801sb_surge_protect_cfg(struct phy_device *phydev)
u16 cl45_value = 0;
if (priv->surge) {
ret = an8801_cl45_read(phydev, 0x1e, 0x174, &cl45_value);
if (ret < 0)
return ret;
cl45_value = phy_read_mmd(phydev, 0x1e, 0x174);
r50ohm_tx_a = (cl45_value >> 8) & 0x007f;
r50ohm_tx_b = cl45_value & 0x007f;
dev_dbg(phydev_dev(phydev), "Read: (0x174) value=0x%04x r50ohm_tx_a=%d r50ohm_tx_b=%d\n",
cl45_value, r50ohm_tx_a, r50ohm_tx_b);
cl45_value, r50ohm_tx_a, r50ohm_tx_b);
ret = process_r50(phydev, 0x174, &cl45_value, &r50ohm_tx_a, &r50ohm_tx_b);
if (ret < 0)
return ret;
ret = an8801_cl45_read(phydev, 0x1e, 0x175, &cl45_value);
if (ret < 0)
return ret;
cl45_value = phy_read_mmd(phydev, 0x1e, 0x175);
r50ohm_tx_c = (cl45_value >> 8) & 0x007f;
r50ohm_tx_d = cl45_value & 0x007f;
dev_dbg(phydev_dev(phydev), "Read: (0x175) value=0x%04x r50ohm_tx_c=%d r50ohm_tx_d=%d\n",
cl45_value, r50ohm_tx_c, r50ohm_tx_d);
cl45_value, r50ohm_tx_c, r50ohm_tx_d);
ret = process_r50(phydev, 0x175, &cl45_value, &r50ohm_tx_c, &r50ohm_tx_d);
if (ret < 0)
return ret;
@@ -764,10 +765,10 @@ static int an8801sb_config_init(struct phy_device *phydev)
dev_info(phydev_dev(phydev),
"Tx, Rx Polarity : %08x\n", pbus_value);
ret = an8801_cl45_write(phydev, MMD_DEV_VSPEC2, 0x600, 0x1e);
ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC2, 0x601, 0x02);
ret = phy_write_mmd(phydev, MMD_DEV_VSPEC2, 0x600, 0x1e);
ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC2, 0x601, 0x02);
ret |= an8801_cl45_write(phydev, 7, 60, 0x0);
ret |= phy_write_mmd(phydev, 7, 60, 0x0);
if (ret != 0) {
dev_err(phydev_dev(phydev),
"AN8801SB initialize fail, ret %d !\n", ret);
@@ -940,7 +941,7 @@ static ssize_t an8801_polarity_write(struct file *file, const char __user *ptr,
}
static ssize_t an8801_mdio_write(struct file *file, const char __user *ptr,
size_t len, loff_t *off)
size_t len, loff_t *off)
{
struct phy_device *phydev = file->private_data;
char buf[64], param1[32], param2[32];
@@ -955,7 +956,7 @@ static ssize_t an8801_mdio_write(struct file *file, const char __user *ptr,
if (count > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, ptr, len))
return -EFAULT;
return -EFAULT;
ret = sscanf(buf, "%s %s", param1, param2);
if (ret < 0)
@@ -991,16 +992,16 @@ static ssize_t an8801_mdio_write(struct file *file, const char __user *ptr,
pr_notice("\nphy=0x%x, devad=0x%x, reg=0x%x, val=0x%x\n",
phydev_phy_addr(phydev), devad, reg, val);
ret = an8801_cl45_write(phydev, devad, reg, val);
ret = phy_write_mmd(phydev, devad, reg, val);
if (ret < 0)
return ret;
an8801_cl45_read(phydev, devad, reg, &reg_val);
reg_val = phy_read_mmd(phydev, devad, reg);
pr_notice("\nphy=0x%x, devad=0x%x, reg=0x%x, val=0x%x confirm..\n",
phydev_phy_addr(phydev), devad, reg, reg_val);
} else if (!strncmp("r", param2, strlen("r"))) {
if (sscanf(buf, "cl45 r %x %x", &devad, &reg) == -1)
return -EFAULT;
an8801_cl45_read(phydev, devad, reg, &reg_val);
reg_val = phy_read_mmd(phydev, devad, reg);
pr_notice("\nphy=0x%x, devad=0x%x, reg=0x%x, val=0x%x\n",
phydev_phy_addr(phydev), devad, reg, reg_val);
} else {
@@ -1020,7 +1021,6 @@ static int an8801_counter_show(struct seq_file *seq, void *v)
struct phy_device *phydev = seq->private;
int ret = 0;
u32 pkt_cnt = 0;
struct mii_bus *mbus = phydev_mdiobus(phydev);
seq_puts(seq, "==========AIR PHY COUNTER==========\n");
seq_puts(seq, "|\t<<SERDES COUNTER>>\n");
@@ -1143,8 +1143,9 @@ static ssize_t an8801_debugfs_pbus(struct file *file,
if (buf[0] == 'w') {
if (sscanf(buf, "w %x %x", &reg, &val) == -1)
return -EFAULT;
pr_notice("\nphy=0x%x, reg=0x%x, val=0x%x\n",
phydev_phy_addr(phydev), reg, val);
phydev_phy_addr(phydev), reg, val);
ret = air_buckpbus_reg_write(phydev, reg, val);
if (ret < 0)
@@ -1188,10 +1189,9 @@ int an8801_info_show(struct seq_file *seq, void *v)
for (reg = MII_BMCR; reg <= MII_STAT1000; reg++) {
if ((reg <= MII_LPA) || (reg >= MII_CTRL1000))
seq_printf(seq, "| RG_MII 0x%02x : 0x%08x\n",
reg, phy_read(phydev, reg));
reg, phy_read(phydev, reg));
}
seq_puts(seq, "\n");
return 0;
}
@@ -1231,10 +1231,10 @@ static const struct file_operations an8801_polarity_fops = {
};
static const struct file_operations an8801_mdio_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.write = an8801_mdio_write,
.llseek = noop_llseek,
.owner = THIS_MODULE,
.open = simple_open,
.write = an8801_mdio_write,
.llseek = noop_llseek,
};
int an8801_debugfs_init(struct phy_device *phydev)
@@ -1354,13 +1354,22 @@ static int an8801sb_read_status(struct phy_device *phydev)
if (phydev->link == LINK_DOWN) {
prespeed = 0;
phydev->speed = 0;
ret |= an8801_cl45_write(
ret |= phy_write_mmd(
phydev, MMD_DEV_VSPEC2, PHY_PRE_SPEED_REG, prespeed);
mdelay(10); /* delay 10 ms */
reg_value = air_buckpbus_reg_read(phydev, 0x10220010);
reg_value &= 0x7fff;
air_buckpbus_reg_write(phydev, 0x10220010, reg_value);
reg_value = air_buckpbus_reg_read(phydev, 0x10220000);
reg_value |= AN8801SB_SGMII_AN0_ANRESTART;
air_buckpbus_reg_write(phydev, 0x10220000, reg_value);
}
if (prespeed != phydev->speed && phydev->link == LINK_UP) {
prespeed = phydev->speed;
ret |= an8801_cl45_write(
ret |= phy_write_mmd(
phydev, MMD_DEV_VSPEC2, PHY_PRE_SPEED_REG, prespeed);
dev_info(phydev_dev(phydev), "AN8801SB SPEED %d\n", prespeed);
while (an_retry > 0) {
@@ -1374,28 +1383,19 @@ static int an8801sb_read_status(struct phy_device *phydev)
mdelay(10); /* delay 10 ms */
if (phydev->autoneg == AUTONEG_DISABLE) {
dev_info(phydev_dev(phydev),
"AN8801SB force speed = %d\n", prespeed);
if (prespeed == SPEED_1000) {
air_buckpbus_reg_write(
phydev, 0x10220010, 0xd801);
} else if (prespeed == SPEED_100) {
air_buckpbus_reg_write(
phydev, 0x10220010, 0xd401);
} else {
air_buckpbus_reg_write(
phydev, 0x10220010, 0xd001);
}
reg_value = air_buckpbus_reg_read(
phydev, 0x10220000);
reg_value |= AN8801SB_SGMII_AN0_ANRESTART;
if (prespeed == SPEED_1000) {
air_buckpbus_reg_write(
phydev, 0x10220000, reg_value);
phydev, 0x10220010, 0xd801);
} else if (prespeed == SPEED_100) {
air_buckpbus_reg_write(
phydev, 0x10220010, 0xd401);
} else {
air_buckpbus_reg_write(
phydev, 0x10220010, 0xd001);
}
reg_value = air_buckpbus_reg_read(phydev, 0x10220000);
reg_value |= AN8801SB_SGMII_AN0_RESET;
reg_value |= (AN8801SB_SGMII_AN0_RESET | AN8801SB_SGMII_AN0_ANRESTART);
air_buckpbus_reg_write(phydev, 0x10220000, reg_value);
}
return ret;
@@ -1451,9 +1451,12 @@ static struct phy_driver airoha_driver[] = {
.probe = an8801_phy_probe,
.remove = an8801_phy_remove,
.read_status = an8801_read_status,
#if (KERNEL_VERSION(4, 5, 0) < LINUX_VERSION_CODE)
.read_mmd = __an8801_cl45_read,
.write_mmd = __an8801_cl45_write,
.config_intr = an8801_config_intr,
#if (KERNEL_VERSION(5, 11, 0) < LINUX_VERSION_CODE)
.handle_interrupt = an8801_handle_interrupt,
#else
.did_interrupt = an8801_did_interrupt,
.ack_interrupt = an8801_ack_interrupt,
#endif
}
};

View File

@@ -12,10 +12,10 @@
/* NAMING DECLARATIONS
*/
#define AN8801_DRIVER_VERSION "1.1.4"
#define AN8801_DRIVER_VERSION "1.1.6"
#define DEBUGFS_COUNTER "counter"
#define DEBUGFS_INFO "driver_info"
#define DEBUGFS_INFO "driver_info"
#define DEBUGFS_PBUS_OP "pbus_op"
#define DEBUGFS_POLARITY "polarity"
#define DEBUGFS_MDIO "mdio"
@@ -88,7 +88,7 @@
#define LED_BLK_EVT_1000M_RX BIT(1)
#define LED_BLK_EVT_1000M_TX BIT(0)
#define UNIT_LED_BLINK_DURATION 1024
#define UNIT_LED_BLINK_DURATION 780
/* Serdes auto negotation restart */
#define AN8801SB_SGMII_AN0_ANRESTART (0x0200)
@@ -135,6 +135,9 @@ For reference only
#define LED_BLINK_DURATION(f) (UNIT_LED_BLINK_DURATION << (f))
#define LED_GPIO_SEL(led, gpio) ((led) << ((gpio) * 3))
/* Interrupt GPIO number, should not conflict with LED */
#define AIR_INTERRUPT_GPIO 3
/* DATA TYPE DECLARATIONS
*/
enum AIR_LED_GPIO_PIN_T {

View File

@@ -587,7 +587,7 @@ static int en8801s_phase1_init(struct phy_device *phydev)
phydev->dev_flags = PHY_STATE_INIT;
dev_info(dev, "Phase1 initialize OK ! (%s)\n", EN8801S_DRIVER_VERSION);
dev_info(dev, "Phase1 initialize OK ! (%s) 10Te TP_IDL fixed.\n", EN8801S_DRIVER_VERSION);
if (priv->pro_version == 4) {
ret = en8801s_phase2_init(phydev);
if (ret != 0) {
@@ -811,14 +811,7 @@ static int en8801s_phase2_init(struct phy_device *phydev)
retry--;
}
pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C38); /* RAW#2 */
ret = airoha_cl45_read(mbus, phy_addr, 0x1E, 0x12, &cl45_value);
if (ret < 0)
return ret;
GPHY_RG_1E_012.DATA = cl45_value;
GPHY_RG_1E_012.DataBitField.da_tx_i2mpb_a_tbt =
(u16)(pbus_data & 0x03f);
ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x12,
GPHY_RG_1E_012.DATA);
ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x12, 0xA018);
if (ret < 0)
return ret;
ret = airoha_cl45_read(mbus, phy_addr, 0x1E, 0x17, &cl45_value);
@@ -893,6 +886,17 @@ static int en8801s_phase2_init(struct phy_device *phydev)
}
}
//Fix 10Te TP_IDL
ret = airoha_cl45_read(mbus, phy_addr, 0x1E,
0x1A3, &cl45_value);
if (ret < 0)
return ret;
cl45_value &= ~0xf0;
ret = airoha_cl45_write(mbus, phy_addr, 0x1E,
0x1A3, cl45_value);
if (ret < 0)
return ret;
priv->first_init = false;
dev_info(phydev_dev(phydev), "Phase2 initialize OK !\n");
return 0;

View File

@@ -31,7 +31,10 @@ mediatek_setup_interfaces()
;;
sonicfi,rap630w-211g)
ucidef_set_interfaces_lan_wan "lan1 lan2 lan3" eth1
;;
;;
emplus,wap588m)
ucidef_set_interfaces_lan_wan "eth0" "eth1"
;;
*)
ucidef_set_interfaces_lan_wan "eth1" "eth0"
;;

View File

@@ -2,7 +2,6 @@ CONFIG_64BIT=y
CONFIG_AHCI_MTK=y
CONFIG_AIROHA_EN8801SC_PHY=y
# CONFIG_AIROHA_EN8811H_PHY is not set
# CONFIG_AIROHA_AN8801_PHY is not set
CONFIG_AN8855_GSW=y
CONFIG_ARCH_CLOCKSOURCE_DATA=y
CONFIG_ARCH_DMA_ADDR_T_64BIT=y

View File

@@ -1,15 +1,3 @@
From 535fdc6dfce7def996a5188819ffc96231c36f98 Mon Sep 17 00:00:00 2001
From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
Date: Tue, 2 Jan 2024 18:13:43 +0800
Subject: [PATCH] [networking][999-2738-an8801sb-gphy-support.patch]
---
drivers/net/phy/Kconfig | 5 +
drivers/net/phy/Makefile | 1 +
2 files changed, 6 insertions(+)
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index ccd3f3f..5dbfb17 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -345,6 +345,11 @@ config SFP
@@ -24,8 +12,6 @@ index ccd3f3f..5dbfb17 100644
config AIROHA_EN8801SC_PHY
tristate "Drivers for Airoha EN8801S Gigabit PHYs for MediaTek SoC."
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 1e8d67b..d39e54b 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -74,6 +74,7 @@ endif
@@ -36,6 +22,64 @@ index 1e8d67b..d39e54b 100644
obj-$(CONFIG_AIROHA_EN8801SC_PHY) += en8801sc.o
air_en8811h-y := air_en8811h_main.o air_en8811h_api.o
obj-$(CONFIG_AIROHA_EN8811H_PHY) += air_en8811h.o
--
2.18.0
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -870,12 +870,17 @@
of_node_put(phy_node);
if (!phy_dev)
- return -ENODEV;
-
+ {
+ phylink_info(pl, "[phylink] reload phy-handle2. %s %d\n",__func__, __LINE__);
+ phy_node = of_parse_phandle(dn, "phy-handle2", 0);
+ phy_dev = of_phy_attach(pl->netdev, phy_node, flags, pl->link_interface);
+ if (!phy_dev)
+ return -ENODEV;
+ }
+
ret = phylink_bringup_phy(pl, phy_dev, pl->link_config.interface);
if (ret)
phy_detach(phy_dev);
-
return ret;
}
EXPORT_SYMBOL_GPL(phylink_of_phy_connect);
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -226,7 +226,9 @@
return rc;
/* Loop over the child nodes and register a phy_device for each phy */
+ int an8801=0;
for_each_available_child_of_node(np, child) {
+ if(an8801==1)break;
addr = of_mdio_parse_addr(&mdio->dev, child);
if (addr < 0) {
scanphys = true;
@@ -234,7 +236,25 @@
}
if (of_mdiobus_child_is_phy(child))
+ {
+ if(addr==30)
+ {
+ int phy_id ;
+
+ phy_id = mdiobus_read(mdio, addr, MII_PHYSID1) << 16 ;
+ phy_id = phy_id + mdiobus_read(mdio, addr, MII_PHYSID2);
+ dev_info(&mdio->dev, "[of_mdio] %s %d addr:%d phy_id:0x%x \n",__func__, __LINE__, addr, phy_id);
+
+ if (phy_id==0 || phy_id==0x1a750000)
+ {
+ dev_info(&mdio->dev, "[of_mdio] %s %d continue \n",__func__, __LINE__);
+ continue;
+ }
+ else
+ an8801=1;
+ }
rc = of_mdiobus_register_phy(mdio, child, addr);
+ }
else
rc = of_mdiobus_register_device(mdio, child, addr);

View File

@@ -53,6 +53,11 @@ $(call Package/ath12k-wifi-default)
TITLE:=board-2.bin for RAP750e_h
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
$(call Package/ath12k-wifi-default)
TITLE:=board-2.bin for RAP750W_311a
@@ -78,6 +83,15 @@ $(call Package/ath12k-wifi-default)
TITLE:=board-2.bin for AP72TIP-v4
endef
define Package/ath12k-wifi-zyxel-nwa130be
$(call Package/ath12k-wifi-default)
TITLE:=board-2.bin for NWA130BE
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
$(INSTALL_DIR) $(1)/lib/firmware/ath12k/QCN92XX/hw1.0/
@@ -109,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
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
$(INSTALL_DIR) $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/
$(INSTALL_DIR) $(1)/lib/firmware/ath12k/QCN6432/hw1.0/
@@ -149,12 +172,29 @@ define Package/ath12k-wifi-sercomm-ap72tip-v4/install
$(INSTALL_DATA) ./board-2.bin.ap72tip-v4.IPQ5332 $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/board-2.bin
endef
define Package/ath12k-wifi-zyxel-nwa130be/install
$(INSTALL_DIR) $(1)/lib/firmware/ath12k/QCN92XX/hw1.0/
$(INSTALL_DIR) $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/
$(INSTALL_DATA) ./board-2.bin.nwa130be.QCN92XX $(1)/lib/firmware/ath12k/QCN92XX/hw1.0/board-2.bin
$(INSTALL_DATA) ./board-2.bin.nwa130be.IPQ5332 $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/board-2.bin
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-edgecore-eap105))
$(eval $(call BuildPackage,ath12k-wifi-sonicfi-rap7110c-341x))
$(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-cig-wf189w))
$(eval $(call BuildPackage,ath12k-wifi-cig-wf189h))
$(eval $(call BuildPackage,ath12k-wifi-sercomm-ap72tip))
$(eval $(call BuildPackage,ath12k-wifi-sercomm-ap72tip-v4))
$(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
+++ b/hostapd/config_file.c
@@ -3003,6 +3003,8 @@ static int hostapd_config_fill(struct ho
@@ -9,12 +10,10 @@
#endif /* CONFIG_IEEE80211R_AP */
#ifndef CONFIG_NO_CTRL_IFACE
} else if (os_strcmp(buf, "ctrl_interface") == 0) {
@@ -4958,8 +4960,22 @@ int hostapd_set_iface(struct hostapd_con
return -1;
}
@@ -4982,6 +4982,19 @@ struct hostapd_config * hostapd_config_r
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) {
+ 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);
@@ -25,14 +24,12 @@
+ 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);
+ 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;
+ }
hostapd_set_security_params(conf->bss[i], 0);
+ }
if (hostapd_config_check(conf, 0)) {
wpa_printf(MSG_ERROR, "Configuration check failed");
hostapd_set_security_params(conf->bss[i], 1);
#ifdef CONFIG_IEEE80211BE
if (conf->ieee80211be && conf->bss[i]->ieee80211w > 0
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -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)
{
struct hostapd_sta_wpa_psk_short *psk = sta->psk;
char addr[sizeof(MACSTR)];
uc_value_t *val, *cur;
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);
if (sta->psk_idx)
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));
val = wpa_ucode_call(3);

View File

@@ -15,9 +15,19 @@ sercomm,ap72tip)
;;
sonicfi,rap7110c-341x|\
sonicfi,rap750e-h|\
sonicfi,rap750e-s|\
sonicfi,rap750w-311a)
ucidef_set_led_default "power" "POWER" "pwm:blue" "on"
;;
zyxel,nwa130be)
#eth0: APPE: phyaddr 4 green:2.5G orange:others
ssdk_sh debug phy set 4 0x40078074 0x670
ssdk_sh debug phy set 4 0x40078078 0x8600
#eth1: MHT: phyaddr 3 green:2.5G orange:others
ssdk_sh debug phy set 3 0x40078074 0x670
ssdk_sh debug phy set 3 0x40078078 0x8600
;;
esac
board_config_flush

View File

@@ -13,13 +13,15 @@ ipq53xx_setup_interfaces()
ucidef_set_interfaces_lan_wan "eth1 eth2 eth3 eth4 eth5" "eth0"
;;
cig,wf189|\
cig,wf672|\
edgecore,eap105|\
sercomm,ap72tip|\
sonicfi,rap750w-311a)
ucidef_set_interfaces_lan_wan "eth1" "eth0"
;;
sonicfi,rap7110c-341x|\
sonicfi,rap750e-h)
sonicfi,rap750e-h|\
sonicfi,rap750e-s)
ucidef_set_interfaces_lan_wan "" "eth0"
;;
cig,wf189w)
@@ -33,6 +35,9 @@ ipq53xx_setup_interfaces()
sercomm,ap72tip-v4)
ucidef_set_interface_wan "eth0"
;;
zyxel,nwa130be)
ucidef_set_interfaces_lan_wan "eth1" "eth0"
;;
esac
}
@@ -40,21 +45,35 @@ qcom_setup_macs()
{
local board="$1"
case $board in
cig,wf189w|\
cig,wf189h|\
cig,wf189w|\
cig,wf189h|\
cig,wf189)
mtd=$(find_mtd_chardev "0:APPSBLENV")
[ -z "$mtd" ] && return;
mac=$(grep eth1addr= $mtd | cut -d= -f2)
mtd=$(find_mtd_chardev "0:APPSBLENV")
[ -z "$mtd" ] && return;
mac=$(grep eth1addr= $mtd | 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)
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)
;;
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)
wan_mac=$(cat /sys/class/net/eth0/address)
@@ -66,9 +85,13 @@ qcom_setup_macs()
edgecore,eap105)
wan_mac=$(cat /sys/class/net/eth0/address)
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,rap750e-h)
sonicfi,rap750e-h|\
sonicfi,rap750e-s)
wan_mac=$(cat /sys/class/net/eth0/address)
ucidef_set_wireless_macaddr_base 2g $(macaddr_add "$wan_mac" 1)
ucidef_set_wireless_macaddr_base 5g $(macaddr_add "$wan_mac" 2)
@@ -87,6 +110,19 @@ qcom_setup_macs()
ucidef_set_wireless_macaddr_base 5g $(macaddr_add "$wan_mac" 2)
ucidef_set_wireless_macaddr_base 6g $(macaddr_add "$wan_mac" 3)
;;
zyxel,nwa130be)
wan_mac=$(cat /proc/cmdline)
wan_mac="${wan_mac##*hwaddr=}"
wan_mac="${wan_mac%% *}"
wan_mac="$(echo ${wan_mac} | sed 's/\(..\)/\1:/g;s/:$//')"
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)
;;
*)
wan_mac=$(cat /sys/class/net/eth1/address)
lan_mac=$(macaddr_add "$wan_mac" 1)

View File

@@ -23,6 +23,39 @@ caldata_extract() {
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)
case "$FIRMWARE" in
ath12k/IPQ5332/hw1.0/caldata.bin)
@@ -32,13 +65,18 @@ ath12k/IPQ5332/hw1.0/caldata.bin)
cig,wf189|\
edgecore,eap105|\
sercomm,ap72tip-v4|\
sercomm,ap72tip)
sercomm,ap72tip|\
zyxel,nwa130be)
caldata_extract "0:ART" 0x1000 0x20000
;;
cig,wf672)
cig_ipq5322_cal
;;
sonicfi,rap7110c-341x)
caldata_extract_mmc "0:ART" 0x1000 0xF800
;;
sonicfi,rap750e-h|\
sonicfi,rap750e-s|\
sonicfi,rap750w-311a)
caldata_extract "0:ART" 0x1000 0xf800
;;
@@ -49,9 +87,13 @@ ath12k/QCN92XX/hw1.0/cal-pci-0001:01:00.0.bin)
cig,wf189|\
edgecore,eap105|\
sercomm,ap72tip-v4|\
sercomm,ap72tip)
sercomm,ap72tip|\
zyxel,nwa130be)
caldata_extract "0:ART" 0x58800 0x2d000
;;
cig,wf672)
cig_qcn92xx_cal
;;
sonicfi,rap7110c-341x)
caldata_extract_mmc "0:ART" 0x58800 0x2d000
;;
@@ -60,6 +102,7 @@ ath12k/QCN92XX/hw1.0/cal-pci-0001:01:00.0.bin)
ath12k/QCN6432/hw1.0/caldata_1.bin)
case "$board" in
sonicfi,rap750e-h|\
sonicfi,rap750e-s|\
sonicfi,rap750w-311a)
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
}
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() {
local tar_file="$1"
local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$')
@@ -86,6 +132,8 @@ platform_do_upgrade() {
board=$(board_name)
case $board in
sercomm,ap72tip-v4|\
sercomm,ap72tip|\
cig,wf189w|\
cig,wf189h|\
cig,wf189)
@@ -98,6 +146,9 @@ platform_do_upgrade() {
fi
nand_upgrade_tar "$1"
;;
cig,wf672)
spi_nor_emmc_do_upgrade_bootconfig $1
;;
edgecore,eap105)
if [ "$(find_mtd_chardev rootfs)" ]; then
CI_UBIPART="rootfs"
@@ -117,12 +168,12 @@ platform_do_upgrade() {
emmc_do_upgrade "$1"
;;
sonicfi,rap750e-h|\
sonicfi,rap750e-s|\
sonicfi,rap750w-311a)
sonicfi_dualimage_check
nand_upgrade_tar "$1"
;;
sercomm,ap72tip-v4|\
sercomm,ap72tip)
zyxel,nwa130be)
nand_upgrade_tar "$1"
;;
esac

View File

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

View File

@@ -18,6 +18,21 @@
model = "CIG WF189";
compatible = "cig,wf189", "qcom,ipq5332-ap-mi01.6", "qcom,ipq5332-rdp468", "qcom,ipq5332";
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
ramoops@49c00000 {
compatible = "ramoops";
no-map;
reg = <0x0 0x49c00000 0x0 0x50000>;
record-size = <0x20000>;
console-size = <0x8000>;
pmsg-size = <0x8000>;
};
};
aliases {
serial0 = &blsp1_uart0;
serial1 = &blsp1_uart1;

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"
/ {
model = "Sercomm WiFi-7";
model = "Sercomm AP72TIP-v4";
compatible = "sercomm,ap72tip-v4", "qcom,ipq5332-ap-mi01.6", "qcom,ipq5332";
aliases {

View File

@@ -15,7 +15,7 @@
#include "ipq5332-default-memory.dtsi"
/ {
model = "Sercomm WiFi-7";
model = "Sercomm AP72TIP";
compatible = "sercomm,ap72tip", "qcom,ipq5332-ap-mi01.6", "qcom,ipq5332";
aliases {
@@ -255,7 +255,7 @@
gpios = <&tca6416 14 GPIO_ACTIVE_HIGH>;
};
};
/*
gpio_keys {
compatible = "gpio-keys";
pinctrl-0 = <&button_pins>;
@@ -263,11 +263,11 @@
button@1 {
label = "rst";
linux,code = <KEY_RESTART>;
gpios = <&tlmm 25 GPIO_ACTIVE_LOW>;
gpios = <&tlmm 1 GPIO_ACTIVE_LOW>;
linux,input-type = <1>;
debounce-interval = <60>;
};
};*/
};
wsi: wsi {
id = <0>;
@@ -546,13 +546,13 @@
drive-strength = <8>;
bias-pull-down;
};*/
/*
button_pins: button-state {
pins = "gpio25";
pins = "gpio1";
function = "gpio";
drive-strength = <8>;
bias-pull-up;
};*/
};
pwm_pins: pwm-state {
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,592 @@
// 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 = "Zyxel NWA130BE";
compatible = "zyxel,nwa130be", "qcom,ipq5332-ap-mi01.6", "qcom,ipq5332-rdp468", "qcom,ipq5332";
aliases {
serial0 = &blsp1_uart0;
serial1 = &blsp1_uart1;
ethernet0 = "/soc/dp1";
ethernet1 = "/soc/dp2";
};
chosen {
stdout-path = "serial0";
};
soc@0 {
mdio:mdio@90000 {
pinctrl-0 = <&mdio1_pins &mdio0_pins>;
pinctrl-names = "default";
/*gpio51 for manhattan reset*/
phy-reset-gpio = <&tlmm 51 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>;
fixup;
};
phy1: ethernet-phy@1 {
reg = <2>;
fixup;
};
phy2: ethernet-phy@2 {
reg = <3>;
fixup;
};
phy3: ethernet-phy@3 {
reg = <4>;
fixup;
};
switch0@10 {
compatible = "qca,qca8386";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x10>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
label = "cpu";
ethernet = <&gmac2>;
dsa-tag-protocol = "qca_4b";
};
port@1 {
reg = <1>;
label = "lan1";
phy-handle = <&phy0>;
phy-mode = "usxgmii";
};
port@2 {
reg = <2>;
label = "lan2";
phy-handle = <&phy1>;
phy-mode = "usxgmii";
};
port@3 {
reg = <3>;
label = "lan3";
phy-handle = <&phy2>;
phy-mode = "usxgmii";
};
};
};
};
ess-instance {
num_devices = <0x2>;
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 = <0xf>; /* mac mode for uniphy instance1*/
switch_mac_mode2 = <0xff>; /* mac mode for uniphy instance2*/
qcom,port_phyinfo {
port@0 {
port_id = <1>;
forced-speed = <2500>;
forced-duplex = <1>;
};
port@1 {
port_id = <2>;
phy_address = <4>;
};
};
led_source@5 {
source = <5>;
mode = "normal";
speed = "all";
blink_en = "enable";
active = "high";
};
};
ess-switch1@1 {
compatible = "qcom,ess-switch-qca8386";
device_id = <1>;
switch_access_mode = "mdio";
mdio-bus = <&mdio>;
switch_mac_mode = <0xc>; /* mac mode for uniphy instance0 */
switch_mac_mode1 = <0xff>; /* mac mode1 for uniphy instance1 */
switch_cpu_bmp = <0x1>; /* cpu port bitmap */
switch_lan_bmp = <0xe>; /* lan port bitmap */
switch_wan_bmp = <0x0>; /* wan port bitmap */
link-polling-required = <0>;
fdb_sync = "interrupt";
link-intr-gpio = <&tlmm 23 GPIO_ACTIVE_HIGH>;
qcom,port_phyinfo {
port@0 {
port_id = <0>;
forced-speed = <2500>;
forced-duplex = <1>;
};
port@1 {
port_id = <1>;
phy_address = <1>;
};
port@2 {
port_id = <2>;
phy_address = <2>;
};
port@3 {
port_id = <3>;
phy_address = <3>;
};
};
led_source@2 {
source = <2>;
mode = "normal";
speed = "all";
blink_en = "enable";
active = "high";
};
led_source@5 {
source = <5>;
mode = "normal";
speed = "all";
blink_en = "enable";
active = "high";
};
led_source@8 {
source = <8>;
mode = "normal";
speed = "all";
blink_en = "enable";
active = "high";
};
};
};
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 = <4>;
qcom,link-poll = <1>;
phy-mode = "sgmii";
};
gmac2:dp2 {
device_type = "network";
compatible = "qcom,nss-dp";
qcom,id = <1>;
reg = <0x3a500000 0x4000>;
qcom,mactype = <1>;
local-mac-address = [000000000000];
phy-mode = "sgmii";
qcom,mht-dev = <1>;
qcom,is_switch_connected = <1>;
qcom,ppe-offload-disabled = <1>;
};
/* 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 */
};
leds {
compatible = "gpio-leds";
pinctrl-0 = <&led_pins>;
pinctrl-names = "default";
led_blue{
label = "led_blue";
gpio = <&tlmm 22 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "led_blue";
default-state = "off";
};
led_green {
label = "led_green";
gpio = <&tlmm 31 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "led_green";
default-state = "on";
};
led_white {
label = "led_white";
gpio = <&tlmm 32 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "led_white";
default-state = "off";
};
led_red {
label = "led_red";
gpio = <&tlmm 44 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "led_red";
default-state = "off";
};
};
gpio_keys {
compatible = "gpio-keys";
pinctrl-0 = <&button_pins>;
pinctrl-names = "default";
button@1 {
label = "reset";
linux,code = <KEY_RESTART>;
gpios = <&tlmm 30 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>;
pinctrl-names = "default";
status = "disabled";
};
&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>;
};
};
&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>;
};
};
&pcie1_phy_x2 {
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 = <0x1019>;
};
};
};
/* PINCTRL */
&tlmm {
led_pins: led_pins {
led_blue {
pins = "gpio22";
function = "gpio";
drive-strength = <8>;
bias-pull-down;
};
led_green {
pins = "gpio31";
function = "gpio";
drive-strength = <8>;
bias-pull-down;
};
led_white {
pins = "gpio32";
function = "gpio";
drive-strength = <8>;
bias-pull-down;
};
led_red {
pins = "gpio44";
function = "gpio";
drive-strength = <8>;
bias-pull-down;
};
};
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;
};
};
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;
};
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;
};
};
serial_1_pins: serial1-pinmux {
pins = "gpio33", "gpio34", "gpio35", "gpio36";
function = "blsp1_uart2";
drive-strength = <8>;
bias-pull-up;
};
button_pins: button-state {
pins = "gpio30";
function = "gpio";
drive-strength = <8>;
bias-pull-up;
};
pwm_pins: pwm-state {
pins = "gpio46";
function = "pwm0";
drive-strength = <8>;
};
pcie1_default_state: pcie1-default-state {
pins = "gpio47";
function = "gpio";
drive-strength = <8>;
bias-pull-up;
output-low;
};
};
&license_manager {
status = "okay";
};
&usb3 {
qcom,multiplexed-phy;
status = "okay";
};
&pwm {
pinctrl-0 = <&pwm_pins>;
pinctrl-names = "default";
status = "okay";
};
&hs_m31phy_0 {
status = "okay";
};
&ssuniphy_0 {
status = "okay";
};

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
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
DEVICE_TITLE := SONICFI RAP750W-311A
DEVICE_DTS := ipq5332-sonicfi-rap750w-311a
@@ -119,3 +133,30 @@ define Device/cig_wf189h
DEVICE_PACKAGES := ath12k-wifi-cig-wf189h ath12k-firmware-ipq5332-peb-peb
endef
TARGET_DEVICES += cig_wf189h
define Device/zyxel_nwa130be
DEVICE_TITLE := Zyxel NWA130BE
DEVICE_DTS := ipq5332-zyxel-nwa130be
DEVICE_DTS_DIR := ../dts
DEVICE_DTS_CONFIG := config@mi01.6
IMAGES := sysupgrade.tar nand-factory.bin nand-factory.ubi
BLOCKSIZE := 256k
PAGESIZE := 4096
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-zyxel-nwa130be ath12k-firmware-qcn92xx ath12k-firmware-ipq5332
endef
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,
channel: format_channel(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_freq2: format_channel(data.center_freq2) || 'unknown',
txpower: data.wiphy_tx_power_level / 100,

View File

@@ -262,6 +262,11 @@ define KernelPackage/mt7601u
AUTOLOAD:=$(call AutoProbe,mt7601u)
endef
ifdef CONFIG_TARGET_PROFILE
TARGET_PROFILE=$(subst ",,$(CONFIG_TARGET_PROFILE))
PATCH_PROFILE_NAME=patches-$(subst DEVICE_,,$(TARGET_PROFILE))
endif
ifdef CONFIG_PACKAGE_MAC80211_DEBUGFS
config-y += \
CFG80211_DEBUGFS \
@@ -362,6 +367,7 @@ define Build/Patch
$(call PatchDir,$(PKG_BUILD_DIR),$(EXTERNAL_PATCH_DIR)/ath12k,ath12k/)
$(call PatchDir,$(PKG_BUILD_DIR),$(EXTERNAL_PATCH_DIR)/pending,pending/)
$(call PatchDir,$(PKG_BUILD_DIR),$(PATCH_TIP_DIR)/pending,pending/)
$(call PatchDir,$(PKG_BUILD_DIR),$(PATCH_PROFILE_NAME)/ath12k,ath12k/)
$(if $(QUILT),touch $(PKG_BUILD_DIR)/.quilt_used)
endef

View File

@@ -0,0 +1,59 @@
From 1a46aa106a50a06bfa4b669d87a8143c3d59f2f4 Mon Sep 17 00:00:00 2001
From: YenLin Pan <yenlin.pan@zyxel.com.tw>
Date: Wed, 14 May 2025 14:14:22 +0800
Subject: [PATCH] thermal: thermal setting
lv0 -100 -hi0 105 -off0 0
lv1 95 -hi1 110 -off1 75
lv2 100 -hi2 115 -off2 98
lv3 105 -hi3 120 -off3 100
Signed-off-by: YenLin Pan <YenLin.Pan@zyxel.com.tw>
---
drivers/net/wireless/ath/ath12k/thermal.h | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/thermal.h b/drivers/net/wireless/ath/ath12k/thermal.h
index 5c91906..a493cd5 100644
--- a/drivers/net/wireless/ath/ath12k/thermal.h
+++ b/drivers/net/wireless/ath/ath12k/thermal.h
@@ -13,28 +13,28 @@
/* Below temperatures are in celsius */
#define ATH12K_THERMAL_LVL0_TEMP_LOW_MARK -100
-#define ATH12K_THERMAL_LVL0_TEMP_HIGH_MARK 100
+#define ATH12K_THERMAL_LVL0_TEMP_HIGH_MARK 105
#define ATH12K_THERMAL_LVL1_TEMP_LOW_MARK 95
-#define ATH12K_THERMAL_LVL1_TEMP_HIGH_MARK 105
+#define ATH12K_THERMAL_LVL1_TEMP_HIGH_MARK 110
#define ATH12K_THERMAL_LVL2_TEMP_LOW_MARK 100
-#define ATH12K_THERMAL_LVL2_TEMP_HIGH_MARK 110
+#define ATH12K_THERMAL_LVL2_TEMP_HIGH_MARK 115
#define ATH12K_THERMAL_LVL3_TEMP_LOW_MARK 105
#define ATH12K_THERMAL_LVL3_TEMP_HIGH_MARK 120
#define ATH12K_THERMAL_LVL0_V2_TEMP_LOW_MARK -100
-#define ATH12K_THERMAL_LVL0_V2_TEMP_HIGH_MARK 95
+#define ATH12K_THERMAL_LVL0_V2_TEMP_HIGH_MARK 105
#define ATH12K_THERMAL_LVL1_V2_TEMP_LOW_MARK 90
-#define ATH12K_THERMAL_LVL1_V2_TEMP_HIGH_MARK 100
+#define ATH12K_THERMAL_LVL1_V2_TEMP_HIGH_MARK 110
#define ATH12K_THERMAL_LVL2_V2_TEMP_LOW_MARK 95
#define ATH12K_THERMAL_LVL2_V2_TEMP_HIGH_MARK 105
#define ATH12K_THERMAL_LVL3_V2_TEMP_LOW_MARK 100
-#define ATH12K_THERMAL_LVL3_V2_TEMP_HIGH_MARK 110
+#define ATH12K_THERMAL_LVL3_V2_TEMP_HIGH_MARK 115
#define ATH12K_THERMAL_LVL4_V2_TEMP_LOW_MARK 105
#define ATH12K_THERMAL_LVL4_V2_TEMP_HIGH_MARK 120
#define ATH12K_THERMAL_LVL0_DUTY_CYCLE 0
-#define ATH12K_THERMAL_LVL1_DUTY_CYCLE 50
-#define ATH12K_THERMAL_LVL2_DUTY_CYCLE 90
+#define ATH12K_THERMAL_LVL1_DUTY_CYCLE 75
+#define ATH12K_THERMAL_LVL2_DUTY_CYCLE 98
#define ATH12K_THERMAL_LVL3_DUTY_CYCLE 100
#define ATH12K_THERMAL_LVL0_V2_DUTY_CYCLE ATH12K_THERMAL_LVL0_DUTY_CYCLE
--
2.34.1

View File

@@ -702,3 +702,44 @@ define KernelPackage/llcc_perfmon/description
endef
$(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

@@ -97,6 +97,11 @@ else ifneq ($(CONFIG_ARCH),)
TARGET_NAME=$(subst ",,$(CONFIG_ARCH))-openwrt-linux$(if $(CONFIG_TARGET_SUFFIX),-$(subst ",,$(CONFIG_TARGET_SUFFIX)))
endif
ifdef CONFIG_TARGET_PROFILE
TARGET_PROFILE=$(subst ",,$(CONFIG_TARGET_PROFILE))
PATCH_PROFILE_NAME=patches-$(subst DEVICE_,,$(TARGET_PROFILE))
endif
QCASSDK_CONFIG_OPTS+= TOOL_PATH=$(TOOLCHAIN_BIN_PATH) \
SYS_PATH=$(LINUX_DIR) \
TOOLPREFIX=$(TARGET_CROSS) \
@@ -193,5 +198,10 @@ define KernelPackage/qca-ssdk-qca-hnat/install
$(INSTALL_BIN) ./files/qca-ssdk $(1)/etc/init.d/qca-ssdk
endef
define patch_profile
$(call PatchDir/Default,$(PKG_BUILD_DIR),./$(PATCH_PROFILE_NAME))
endef
Hooks/Prepare/Post += patch_profile
$(eval $(call KernelPackage,qca-ssdk-qca-nohnat))
$(eval $(call KernelPackage,qca-ssdk-qca-hnat))

View File

@@ -0,0 +1,47 @@
From 7fa9e9b683f1c573c58a14755347988919bc7d06 Mon Sep 17 00:00:00 2001
From: YenLin Pan <yenlin.pan@zyxel.com.tw>
Date: Wed, 14 May 2025 13:47:06 +0800
Subject: [PATCH] pinctrl: make the switch LED works
Enable switch LED pin definition for LED0/LED1/LED2 control
Signed-off-by: YenLin Pan <YenLin.Pan@zyxel.com.tw>
---
src/init/ssdk_mht_pinctrl.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/init/ssdk_mht_pinctrl.c b/src/init/ssdk_mht_pinctrl.c
index 2debe59..1ae0002 100755
--- a/src/init/ssdk_mht_pinctrl.c
+++ b/src/init/ssdk_mht_pinctrl.c
@@ -33,11 +33,17 @@ static struct mht_pinctrl_setting mht_pin_settings[] = {
/*PINs default MUX Setting*/
MHT_PIN_SETTING_MUX(0, MHT_PIN_FUNC_INTN_WOL),
MHT_PIN_SETTING_MUX(1, MHT_PIN_FUNC_INTN),
-#if 0
+#if 1
MHT_PIN_SETTING_MUX(2, MHT_PIN_FUNC_P0_LED_0),
MHT_PIN_SETTING_MUX(3, MHT_PIN_FUNC_P1_LED_0),
MHT_PIN_SETTING_MUX(4, MHT_PIN_FUNC_P2_LED_0),
MHT_PIN_SETTING_MUX(5, MHT_PIN_FUNC_P3_LED_0),
+ MHT_PIN_SETTING_MUX(6, MHT_PIN_FUNC_P0_LED_2),
+ MHT_PIN_SETTING_MUX(7, MHT_PIN_FUNC_P1_LED_2),
+ MHT_PIN_SETTING_MUX(8, MHT_PIN_FUNC_P2_LED_2),
+ MHT_PIN_SETTING_MUX(9, MHT_PIN_FUNC_P3_LED_2),
+#endif
+#if 0
MHT_PIN_SETTING_MUX(6, MHT_PIN_FUNC_PPS_IN),
MHT_PIN_SETTING_MUX(7, MHT_PIN_FUNC_TOD_IN),
MHT_PIN_SETTING_MUX(8, MHT_PIN_FUNC_RTC_REFCLK_IN),
@@ -49,7 +55,7 @@ static struct mht_pinctrl_setting mht_pin_settings[] = {
MHT_PIN_SETTING_MUX(13, MHT_PIN_FUNC_P0_TOD_OUT),
MHT_PIN_SETTING_MUX(14, MHT_PIN_FUNC_P0_CLK125_TDI),
MHT_PIN_SETTING_MUX(15, MHT_PIN_FUNC_P0_SYNC_CLKO_PTP),
-#if 0
+#if 1
MHT_PIN_SETTING_MUX(16, MHT_PIN_FUNC_P0_LED_1),
MHT_PIN_SETTING_MUX(17, MHT_PIN_FUNC_P1_LED_1),
MHT_PIN_SETTING_MUX(18, MHT_PIN_FUNC_P2_LED_1),
--
2.34.1

View File

@@ -25,6 +25,10 @@ cig,wf660a)
mmc_dev=$(echo $(find_mmc_part "0:ETHPHYFW") | sed 's/^.\{5\}//')
[ -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)
mmc_dev=$(echo $(find_mmc_part "certificates") | sed 's/^.\{5\}//')
[ -n "$mmc_dev" ] && mount -t squashfs /dev/$mmc_dev /certificates
@@ -82,6 +86,8 @@ cig,wf189|\
cig,wf189w|\
cig,wf189h|\
cig,wf186h|\
cig,wf196|\
cig,wf188n|\
yuncore,ax840|\
yuncore,fap655)
PART_NAME=rootfs_1

View File

@@ -19,6 +19,7 @@ switch(board_name) {
case 'edgecore,eap105':
case 'edgecore,oap101-6e':
case 'edgecore,oap101e-6e':
case 'zyxel,nwa130be':
num_radios = 3;
break;
}

View File

@@ -4,10 +4,10 @@ PKG_NAME:=ucentral-schema
PKG_RELEASE:=1
PKG_SOURCE_URL=https://github.com/Telecominfraproject/wlan-ucentral-schema.git
PKG_MIRROR_HASH:=4788da65803c8674c5d983b2be6d50960708d7adb1bd86cbf62a763b88a1f6d8
PKG_MIRROR_HASH:=ee5d5073bd9ae88590e419f94eb6c59f04a2fc0c3117be435bcb885e0ea28bf1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2025-01-27
PKG_SOURCE_VERSION:=6faaa1f655e3fbf4b5f915c9782634a5a89c2be7
PKG_SOURCE_VERSION:=b4cfdc6a1caa279ae8c6c42b6932620fb2aed9c1
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
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
include:
- ucentral-ap
- hostapd
diffconfig: |
# CONFIG_PACKAGE_kmod-nft-offload 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

View File

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