Lines Matching +full:child +full:- +full:interrupt +full:- +full:base

1 // SPDX-License-Identifier: GPL-2.0
15 #include <linux/devm-helpers.h>
16 #include <linux/interrupt.h>
123 #define AMS_ALARM_THR_MAX (BIT(16) - 1)
164 #define AMS_TEMP_OFFSET -((280230LL << 16) / 509314)
267 * struct ams - This structure contains necessary state for xilinx-ams to operate
268 * @base: physical base address of device
269 * @ps_base: physical base address of PS device
270 * @pl_base: physical base address of PL device
274 * @intr_lock: to protect interrupt mask values
277 * @intr_mask: interrupt configuration
278 * @ams_unmask_work: re-enables event once the event condition disappears
282 void __iomem *base; member
300 val = readl(ams->ps_base + offset); in ams_ps_update_reg()
302 writel(regval, ams->ps_base + offset); in ams_ps_update_reg()
310 val = readl(ams->pl_base + offset); in ams_pl_update_reg()
312 writel(regval, ams->pl_base + offset); in ams_pl_update_reg()
319 ams->intr_mask = (ams->intr_mask & ~mask) | (val & mask); in ams_update_intrmask()
321 regval = ~(ams->intr_mask | ams->current_masked_alarm); in ams_update_intrmask()
322 writel(regval, ams->base + AMS_IER_0); in ams_update_intrmask()
324 regval = ~(FIELD_GET(AMS_ISR1_INTR_MASK, ams->intr_mask)); in ams_update_intrmask()
325 writel(regval, ams->base + AMS_IER_1); in ams_update_intrmask()
327 regval = ams->intr_mask | ams->current_masked_alarm; in ams_update_intrmask()
328 writel(regval, ams->base + AMS_IDR_0); in ams_update_intrmask()
330 regval = FIELD_GET(AMS_ISR1_INTR_MASK, ams->intr_mask); in ams_update_intrmask()
331 writel(regval, ams->base + AMS_IDR_1); in ams_update_intrmask()
337 if (ams->ps_base) { in ams_disable_all_alarms()
345 if (ams->pl_base) { in ams_disable_all_alarms()
396 if (ams->ps_base) in ams_update_alarm()
399 if (ams->pl_base) in ams_update_alarm()
402 spin_lock_irqsave(&ams->intr_lock, flags); in ams_update_alarm()
404 spin_unlock_irqrestore(&ams->intr_lock, flags); in ams_update_alarm()
421 for (i = 0; i < indio_dev->num_channels; i++) { in ams_enable_channel_sequence()
422 const struct iio_chan_spec *chan = &indio_dev->channels[i]; in ams_enable_channel_sequence()
424 if (chan->scan_index < AMS_CTRL_SEQ_BASE) in ams_enable_channel_sequence()
425 scan_mask |= BIT_ULL(chan->scan_index); in ams_enable_channel_sequence()
428 if (ams->ps_base) { in ams_enable_channel_sequence()
435 writel(regval, ams->ps_base + AMS_REG_SEQ_CH0); in ams_enable_channel_sequence()
438 writel(regval, ams->ps_base + AMS_REG_SEQ_CH2); in ams_enable_channel_sequence()
445 if (ams->pl_base) { in ams_enable_channel_sequence()
454 writel(regval, ams->pl_base + AMS_REG_SEQ_CH0); in ams_enable_channel_sequence()
457 writel(regval, ams->pl_base + AMS_REG_SEQ_CH1); in ams_enable_channel_sequence()
460 writel(regval, ams->pl_base + AMS_REG_SEQ_CH2); in ams_enable_channel_sequence()
475 if (ams->ps_base) { in ams_init_device()
476 writel(AMS_PS_RESET_VALUE, ams->ps_base + AMS_VP_VN); in ams_init_device()
478 ret = readl_poll_timeout(ams->base + AMS_PS_CSTS, reg, (reg & expect), in ams_init_device()
488 if (ams->pl_base) { in ams_init_device()
489 value = readl(ams->base + AMS_PL_CSTS); in ams_init_device()
493 writel(AMS_PL_RESET_VALUE, ams->pl_base + AMS_VP_VN); in ams_init_device()
502 /* Disable interrupt */ in ams_init_device()
505 /* Clear any pending interrupt */ in ams_init_device()
506 writel(AMS_ISR0_ALARM_MASK, ams->base + AMS_ISR_0); in ams_init_device()
507 writel(AMS_ISR1_ALARM_MASK, ams->base + AMS_ISR_1); in ams_init_device()
515 return sysfs_emit(label, "%s\n", chan->datasheet_name); in ams_read_label()
545 return -EINVAL; in ams_enable_single_channel()
573 /* clear end-of-conversion flag, wait for next conversion to complete */ in ams_read_vcc_reg()
574 writel(expect, ams->base + AMS_ISR_1); in ams_read_vcc_reg()
575 ret = readl_poll_timeout(ams->base + AMS_ISR_1, reg, (reg & expect), in ams_read_vcc_reg()
580 *data = readl(ams->base + offset); in ams_read_vcc_reg()
630 regval = readl(ams->pl_base + AMS_REG_CONFIG4); in ams_get_pl_scale()
637 regval = readl(ams->pl_base + AMS_REG_CONFIG4); in ams_get_pl_scale()
644 regval = readl(ams->pl_base + AMS_REG_CONFIG4); in ams_get_pl_scale()
651 regval = readl(ams->pl_base + AMS_REG_CONFIG4); in ams_get_pl_scale()
700 mutex_lock(&ams->lock); in ams_read_raw()
701 if (chan->scan_index >= AMS_CTRL_SEQ_BASE) { in ams_read_raw()
702 ret = ams_read_vcc_reg(ams, chan->address, val); in ams_read_raw()
706 } else if (chan->scan_index >= AMS_PS_SEQ_MAX) in ams_read_raw()
707 *val = readl(ams->pl_base + chan->address); in ams_read_raw()
709 *val = readl(ams->ps_base + chan->address); in ams_read_raw()
713 mutex_unlock(&ams->lock); in ams_read_raw()
716 switch (chan->type) { in ams_read_raw()
718 if (chan->scan_index < AMS_PS_SEQ_MAX) in ams_read_raw()
719 *val = ams_get_ps_scale(chan->address); in ams_read_raw()
720 else if (chan->scan_index >= AMS_PS_SEQ_MAX && in ams_read_raw()
721 chan->scan_index < AMS_CTRL_SEQ_BASE) in ams_read_raw()
722 *val = ams_get_pl_scale(ams, chan->address); in ams_read_raw()
724 *val = ams_get_ctrl_scale(chan->address); in ams_read_raw()
733 return -EINVAL; in ams_read_raw()
740 return -EINVAL; in ams_read_raw()
749 scan_index -= AMS_PS_SEQ_MAX; in ams_get_alarm_offset()
798 event -= AMS_PL_ALARM_START; in ams_event_to_channel()
846 for (i = 0; i < dev->num_channels; i++) in ams_event_to_channel()
847 if (dev->channels[i].scan_index == scan_index) in ams_event_to_channel()
850 return &dev->channels[i]; in ams_event_to_channel()
859 scan_index -= AMS_PS_SEQ_MAX; in ams_get_alarm_mask()
901 return !!(ams->alarm_mask & ams_get_alarm_mask(chan->scan_index)); in ams_read_event_config()
913 alarm = ams_get_alarm_mask(chan->scan_index); in ams_write_event_config()
915 mutex_lock(&ams->lock); in ams_write_event_config()
918 ams->alarm_mask |= alarm; in ams_write_event_config()
920 ams->alarm_mask &= ~alarm; in ams_write_event_config()
922 ams_update_alarm(ams, ams->alarm_mask); in ams_write_event_config()
924 mutex_unlock(&ams->lock); in ams_write_event_config()
936 unsigned int offset = ams_get_alarm_offset(chan->scan_index, dir); in ams_read_event_value()
938 mutex_lock(&ams->lock); in ams_read_event_value()
940 if (chan->scan_index >= AMS_PS_SEQ_MAX) in ams_read_event_value()
941 *val = readl(ams->pl_base + offset); in ams_read_event_value()
943 *val = readl(ams->ps_base + offset); in ams_read_event_value()
945 mutex_unlock(&ams->lock); in ams_read_event_value()
959 mutex_lock(&ams->lock); in ams_write_event_value()
962 if (chan->type == IIO_TEMP) { in ams_write_event_value()
963 offset = ams_get_alarm_offset(chan->scan_index, IIO_EV_DIR_FALLING); in ams_write_event_value()
965 if (chan->scan_index >= AMS_PS_SEQ_MAX) in ams_write_event_value()
975 offset = ams_get_alarm_offset(chan->scan_index, dir); in ams_write_event_value()
976 if (chan->scan_index >= AMS_PS_SEQ_MAX) in ams_write_event_value()
977 writel(val, ams->pl_base + offset); in ams_write_event_value()
979 writel(val, ams->ps_base + offset); in ams_write_event_value()
981 mutex_unlock(&ams->lock); in ams_write_event_value()
992 if (chan->type == IIO_TEMP) { in ams_handle_event()
994 * The temperature channel only supports over-temperature in ams_handle_event()
998 IIO_UNMOD_EVENT_CODE(chan->type, chan->channel, in ams_handle_event()
1009 IIO_UNMOD_EVENT_CODE(chan->type, chan->channel, in ams_handle_event()
1025 * ams_unmask_worker - ams alarm interrupt unmask worker
1029 * threshold condition go way from within the interrupt handler, this means as
1030 * soon as a threshold condition is present we would enter the interrupt handler
1032 * in the interrupt handler and start a timer. In this timer we poll the
1033 * interrupt status and only if the interrupt is inactive we unmask it again.
1040 spin_lock_irq(&ams->intr_lock); in ams_unmask_worker()
1042 status = readl(ams->base + AMS_ISR_0); in ams_unmask_worker()
1045 unmask = (ams->current_masked_alarm ^ status) & ams->current_masked_alarm; in ams_unmask_worker()
1048 unmask |= ams->intr_mask; in ams_unmask_worker()
1050 ams->current_masked_alarm &= status; in ams_unmask_worker()
1053 ams->current_masked_alarm &= ~ams->intr_mask; in ams_unmask_worker()
1056 writel(unmask, ams->base + AMS_ISR_0); in ams_unmask_worker()
1060 spin_unlock_irq(&ams->intr_lock); in ams_unmask_worker()
1062 /* If still pending some alarm re-trigger the timer */ in ams_unmask_worker()
1063 if (ams->current_masked_alarm) in ams_unmask_worker()
1064 schedule_delayed_work(&ams->ams_unmask_work, in ams_unmask_worker()
1074 spin_lock(&ams->intr_lock); in ams_irq()
1076 isr0 = readl(ams->base + AMS_ISR_0); in ams_irq()
1079 isr0 &= ~((ams->intr_mask & AMS_ISR0_ALARM_MASK) | ams->current_masked_alarm); in ams_irq()
1081 spin_unlock(&ams->intr_lock); in ams_irq()
1085 /* Clear interrupt */ in ams_irq()
1086 writel(isr0, ams->base + AMS_ISR_0); in ams_irq()
1089 ams->current_masked_alarm |= isr0; in ams_irq()
1094 schedule_delayed_work(&ams->ams_unmask_work, in ams_irq()
1097 spin_unlock(&ams->intr_lock); in ams_irq()
1192 struct fwnode_handle *child; in ams_get_ext_chan() local
1196 fwnode_for_each_child_node(chan_node, child) { in ams_get_ext_chan()
1197 ret = fwnode_property_read_u32(child, "reg", &reg); in ams_get_ext_chan()
1202 ext_chan = reg + AMS_PL_MAX_FIXED_CHANNEL - 30; in ams_get_ext_chan()
1205 if (fwnode_property_read_bool(child, "xlnx,bipolar")) in ams_get_ext_chan()
1206 chan->scan_type.sign = 's'; in ams_get_ext_chan()
1218 iounmap(ams->ps_base); in ams_iounmap_ps()
1225 iounmap(ams->pl_base); in ams_iounmap_pl()
1232 struct device *dev = indio_dev->dev.parent; in ams_init_module()
1237 if (fwnode_device_is_compatible(fwnode, "xlnx,zynqmp-ams-ps")) { in ams_init_module()
1238 ams->ps_base = fwnode_iomap(fwnode, 0); in ams_init_module()
1239 if (!ams->ps_base) in ams_init_module()
1240 return -ENXIO; in ams_init_module()
1248 } else if (fwnode_device_is_compatible(fwnode, "xlnx,zynqmp-ams-pl")) { in ams_init_module()
1249 ams->pl_base = fwnode_iomap(fwnode, 0); in ams_init_module()
1250 if (!ams->pl_base) in ams_init_module()
1251 return -ENXIO; in ams_init_module()
1262 } else if (fwnode_device_is_compatible(fwnode, "xlnx,zynqmp-ams")) { in ams_init_module()
1267 return -EINVAL; in ams_init_module()
1277 struct device *dev = indio_dev->dev.parent; in ams_parse_firmware()
1289 return -ENOMEM; in ams_parse_firmware()
1299 device_for_each_child_node_scoped(dev, child) { in ams_parse_firmware()
1300 ret = ams_init_module(indio_dev, child, ams_channels + num_channels); in ams_parse_firmware()
1320 ams->pl_base + falling_off); in ams_parse_firmware()
1322 ams->pl_base + rising_off); in ams_parse_firmware()
1325 ams->ps_base + falling_off); in ams_parse_firmware()
1327 ams->ps_base + rising_off); in ams_parse_firmware()
1335 return -ENOMEM; in ams_parse_firmware()
1337 indio_dev->channels = dev_channels; in ams_parse_firmware()
1338 indio_dev->num_channels = num_channels; in ams_parse_firmware()
1353 { .compatible = "xlnx,zynqmp-ams" },
1365 indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*ams)); in ams_probe()
1367 return -ENOMEM; in ams_probe()
1370 mutex_init(&ams->lock); in ams_probe()
1371 spin_lock_init(&ams->intr_lock); in ams_probe()
1373 indio_dev->name = "xilinx-ams"; in ams_probe()
1375 indio_dev->info = &iio_ams_info; in ams_probe()
1376 indio_dev->modes = INDIO_DIRECT_MODE; in ams_probe()
1378 ams->base = devm_platform_ioremap_resource(pdev, 0); in ams_probe()
1379 if (IS_ERR(ams->base)) in ams_probe()
1380 return PTR_ERR(ams->base); in ams_probe()
1382 ams->clk = devm_clk_get_enabled(&pdev->dev, NULL); in ams_probe()
1383 if (IS_ERR(ams->clk)) in ams_probe()
1384 return PTR_ERR(ams->clk); in ams_probe()
1386 ret = devm_delayed_work_autocancel(&pdev->dev, &ams->ams_unmask_work, in ams_probe()
1393 return dev_err_probe(&pdev->dev, ret, "failure in parsing DT\n"); in ams_probe()
1397 return dev_err_probe(&pdev->dev, ret, "failed to initialize AMS\n"); in ams_probe()
1405 ret = devm_request_irq(&pdev->dev, irq, &ams_irq, 0, "ams-irq", in ams_probe()
1408 return dev_err_probe(&pdev->dev, ret, "failed to register interrupt\n"); in ams_probe()
1412 return devm_iio_device_register(&pdev->dev, indio_dev); in ams_probe()
1419 clk_disable_unprepare(ams->clk); in ams_suspend()
1428 return clk_prepare_enable(ams->clk); in ams_resume()
1436 .name = "xilinx-ams",