0001
0002
0003
0004
0005
0006
0007 #include <linux/kernel.h>
0008 #include <linux/interrupt.h>
0009 #include <linux/irqdomain.h>
0010 #include <linux/platform_device.h>
0011 #include <asm/cpm1.h>
0012
0013 struct cpm_pic_data {
0014 cpic8xx_t __iomem *reg;
0015 struct irq_domain *host;
0016 };
0017
0018 static void cpm_mask_irq(struct irq_data *d)
0019 {
0020 struct cpm_pic_data *data = irq_data_get_irq_chip_data(d);
0021 unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d);
0022
0023 clrbits32(&data->reg->cpic_cimr, (1 << cpm_vec));
0024 }
0025
0026 static void cpm_unmask_irq(struct irq_data *d)
0027 {
0028 struct cpm_pic_data *data = irq_data_get_irq_chip_data(d);
0029 unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d);
0030
0031 setbits32(&data->reg->cpic_cimr, (1 << cpm_vec));
0032 }
0033
0034 static void cpm_end_irq(struct irq_data *d)
0035 {
0036 struct cpm_pic_data *data = irq_data_get_irq_chip_data(d);
0037 unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d);
0038
0039 out_be32(&data->reg->cpic_cisr, (1 << cpm_vec));
0040 }
0041
0042 static struct irq_chip cpm_pic = {
0043 .name = "CPM PIC",
0044 .irq_mask = cpm_mask_irq,
0045 .irq_unmask = cpm_unmask_irq,
0046 .irq_eoi = cpm_end_irq,
0047 };
0048
0049 static int cpm_get_irq(struct irq_desc *desc)
0050 {
0051 struct cpm_pic_data *data = irq_desc_get_handler_data(desc);
0052 int cpm_vec;
0053
0054
0055
0056
0057
0058 out_be16(&data->reg->cpic_civr, 1);
0059 cpm_vec = in_be16(&data->reg->cpic_civr);
0060 cpm_vec >>= 11;
0061
0062 return irq_linear_revmap(data->host, cpm_vec);
0063 }
0064
0065 static void cpm_cascade(struct irq_desc *desc)
0066 {
0067 generic_handle_irq(cpm_get_irq(desc));
0068 }
0069
0070 static int cpm_pic_host_map(struct irq_domain *h, unsigned int virq,
0071 irq_hw_number_t hw)
0072 {
0073 irq_set_chip_data(virq, h->host_data);
0074 irq_set_status_flags(virq, IRQ_LEVEL);
0075 irq_set_chip_and_handler(virq, &cpm_pic, handle_fasteoi_irq);
0076 return 0;
0077 }
0078
0079 static const struct irq_domain_ops cpm_pic_host_ops = {
0080 .map = cpm_pic_host_map,
0081 };
0082
0083 static int cpm_pic_probe(struct platform_device *pdev)
0084 {
0085 struct device *dev = &pdev->dev;
0086 struct resource *res;
0087 int irq;
0088 struct cpm_pic_data *data;
0089
0090 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0091 if (!res)
0092 return -ENODEV;
0093
0094 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
0095 if (!data)
0096 return -ENOMEM;
0097
0098 data->reg = devm_ioremap(dev, res->start, resource_size(res));
0099 if (!data->reg)
0100 return -ENODEV;
0101
0102 irq = platform_get_irq(pdev, 0);
0103 if (irq < 0)
0104 return irq;
0105
0106
0107 out_be32(&data->reg->cpic_cicr,
0108 (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
0109 ((virq_to_hw(irq) / 2) << 13) | CICR_HP_MASK);
0110
0111 out_be32(&data->reg->cpic_cimr, 0);
0112
0113 data->host = irq_domain_add_linear(dev->of_node, 64, &cpm_pic_host_ops, data);
0114 if (!data->host)
0115 return -ENODEV;
0116
0117 irq_set_handler_data(irq, data);
0118 irq_set_chained_handler(irq, cpm_cascade);
0119
0120 setbits32(&data->reg->cpic_cicr, CICR_IEN);
0121
0122 return 0;
0123 }
0124
0125 static const struct of_device_id cpm_pic_match[] = {
0126 {
0127 .compatible = "fsl,cpm1-pic",
0128 }, {
0129 .type = "cpm-pic",
0130 .compatible = "CPM",
0131 }, {},
0132 };
0133
0134 static struct platform_driver cpm_pic_driver = {
0135 .driver = {
0136 .name = "cpm-pic",
0137 .of_match_table = cpm_pic_match,
0138 },
0139 .probe = cpm_pic_probe,
0140 };
0141
0142 static int __init cpm_pic_init(void)
0143 {
0144 return platform_driver_register(&cpm_pic_driver);
0145 }
0146 arch_initcall(cpm_pic_init);
0147
0148
0149
0150
0151
0152
0153
0154 static irqreturn_t cpm_error_interrupt(int irq, void *dev)
0155 {
0156 return IRQ_HANDLED;
0157 }
0158
0159 static int cpm_error_probe(struct platform_device *pdev)
0160 {
0161 int irq;
0162
0163 irq = platform_get_irq(pdev, 0);
0164 if (irq < 0)
0165 return irq;
0166
0167 return request_irq(irq, cpm_error_interrupt, IRQF_NO_THREAD, "error", NULL);
0168 }
0169
0170 static const struct of_device_id cpm_error_ids[] = {
0171 { .compatible = "fsl,cpm1" },
0172 { .type = "cpm" },
0173 {},
0174 };
0175
0176 static struct platform_driver cpm_error_driver = {
0177 .driver = {
0178 .name = "cpm-error",
0179 .of_match_table = cpm_error_ids,
0180 },
0181 .probe = cpm_error_probe,
0182 };
0183
0184 static int __init cpm_error_init(void)
0185 {
0186 return platform_driver_register(&cpm_error_driver);
0187 }
0188 subsys_initcall(cpm_error_init);