/** * struct aw_bin - Store the data obtained from parsing the configuration file. * @chip_type: Frame header information-chip type * @valid_data_len: Length of valid data obtained after parsing * @valid_data_addr: The offset address of the valid data obtained * after parsing relative to info * @len: The size of the bin file obtained from the firmware * @data: Store the bin file obtained from the firmware
*/ struct aw_bin { unsignedchar chip_type[8]; unsignedint valid_data_len; unsignedint valid_data_addr; unsignedint len; unsignedchar data[] __counted_by(len);
};
struct aw96103 { unsignedint hostirqen; struct regmap *regmap; struct device *dev; /* * There is one more logical channel than the actual channels, * and the extra logical channel is used for temperature detection * but not for status detection. The specific channel used for * temperature detection is determined by the register configuration.
*/ struct aw_channels_info channels_arr[6]; unsignedint max_channels; unsignedint chan_en;
};
ret = regmap_read(aw96103->regmap, AW96103_REG_FWVER2, &fw_ver); if (ret) return ret; /* * If the chip version is AW96103A and the loaded register * configuration file is for AW96103, special handling of the * AW96103_REG_BLRSTRNG_CH0 register is required.
*/ if ((fw_ver != AW96103A) || (aw_bin->chip_type[7] != '\0')) return 0;
for (i = 0; i < aw96103->max_channels; i++) {
ret = regmap_read(aw96103->regmap,
AW96103_REG_BLFILT_CH0 + (AW96103_BLFILT_CH_STEP * i),
&blfilt1_data); if (ret) return ret; if (FIELD_GET(AW96103_BLERRTRIG_MASK, blfilt1_data) != 1) return 0;
ret = regmap_update_bits(aw96103->regmap,
AW96103_REG_BLRSTRNG_CH0 + (AW96103_BLFILT_CH_STEP * i),
AW96103_BLRSTRNG_MASK, 1 << i); if (ret) return ret;
}
return 0;
}
staticint aw96103_bin_valid_loaded(struct aw96103 *aw96103, struct aw_bin *aw_bin_data_s)
{ unsignedint start_addr = aw_bin_data_s->valid_data_addr;
u32 i, reg_data;
u16 reg_addr; int ret;
for (i = 0; i < aw_bin_data_s->valid_data_len;
i += 6, start_addr += 6) {
reg_addr = get_unaligned_le16(aw_bin_data_s->data + start_addr);
reg_data = get_unaligned_le32(aw_bin_data_s->data +
start_addr + 2); if ((reg_addr == AW96103_REG_EEDA0) ||
(reg_addr == AW96103_REG_EEDA1)) continue; if (reg_addr == AW96103_REG_IRQEN) {
aw96103->hostirqen = reg_data; continue;
} if (reg_addr == AW96103_REG_SCANCTRL0)
aw96103->chan_en = FIELD_GET(AW96103_CHAN_EN_MASK,
reg_data);
ret = regmap_write(aw96103->regmap, reg_addr, reg_data); if (ret < 0) return ret;
}
ret = aw96103_reg_version_comp(aw96103, aw_bin_data_s); if (ret) return ret;
return aw96103_channel_scan_start(aw96103);
}
staticint aw96103_para_loaded(struct aw96103 *aw96103)
{ int i, ret;
for (i = 0; i < ARRAY_SIZE(aw96103_reg_default); i += 2) {
ret = regmap_write(aw96103->regmap,
(u16)aw96103_reg_default[i],
(u32)aw96103_reg_default[i + 1]); if (ret) return ret; if (aw96103_reg_default[i] == AW96103_REG_IRQEN)
aw96103->hostirqen = aw96103_reg_default[i + 1]; elseif (aw96103_reg_default[i] == AW96103_REG_SCANCTRL0)
aw96103->chan_en = FIELD_GET(AW96103_CHAN_EN_MASK,
aw96103_reg_default[i + 1]);
}
if (!fw || !fw->data) {
dev_err(aw96103->dev, "No firmware.\n"); return;
}
ret = aw96103_cfg_all_loaded(fw, aw96103); /* * If loading the register configuration file fails, * load the default register configuration in the driver to * ensure the basic functionality of the device.
*/ if (ret) {
ret = aw96103_para_loaded(aw96103); if (ret) {
dev_err(aw96103->dev, "load param error.\n"); return;
}
}
for (i = 0; i < aw96103->max_channels; i++) { if ((aw96103->chan_en >> i) & 0x01)
aw96103->channels_arr[i].used = true; else
aw96103->channels_arr[i].used = false;
}
}
staticint aw96103_sw_reset(struct aw96103 *aw96103)
{ int ret;
ret = regmap_write(aw96103->regmap, AW96103_REG_RESET, 0); /* * After reset, the initialization process starts to perform and * it will last for a bout 20ms.
*/
msleep(20);
ret = regmap_read(aw96103->regmap, AW96103_REG_IRQSRC, &irq_status); if (ret) return IRQ_HANDLED;
ret = regmap_read(aw96103->regmap, AW96103_REG_STAT0, &curr_status_val); if (ret) return IRQ_HANDLED;
/* * Iteratively analyze the interrupt status of different channels, * with each channel having 4 interrupt states.
*/ for (i = 0; i < aw96103->max_channels; i++) { if (!aw96103->channels_arr[i].used) continue;
switch (curr_status) { case FAR:
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, i,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
iio_get_time_ns(indio_dev)); break; case TRIGGER_TH0: case TRIGGER_TH1: case TRIGGER_TH2: case TRIGGER_TH3:
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, i,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
iio_get_time_ns(indio_dev)); break; default: return IRQ_HANDLED;
}
aw96103->channels_arr[i].old_irq_status = curr_status;
}
while (cnt--) { /* * The device should generate an initialization completion * interrupt within 20ms.
*/
ret = regmap_read(aw96103->regmap, AW96103_REG_IRQSRC,
®_data); if (ret) return ret;
if (FIELD_GET(AW96103_INITOVERIRQ_MASK, reg_data)) return 0;
fsleep(1000);
}
while (cnt < 3) { /* * This retry mechanism and the subsequent delay are just * attempts to read the chip ID as much as possible, * preventing occasional communication failures from causing * the chip ID read to fail.
*/
ret = regmap_read(aw96103->regmap, AW96103_REG_CHIPID,
®_val); if (ret < 0) {
cnt++;
fsleep(2000); continue;
} break;
} if (cnt == 3) return -ETIMEDOUT;
if (FIELD_GET(AW96103_CHIPID_MASK, reg_val) != AW96103_CHIP_ID)
dev_info(aw96103->dev, "unexpected chipid, id=0x%08X\n", reg_val);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.