This source file includes following definitions.
- mb_chan_send_msg
- mb_chan_recv_msg
- mb_chan_status_ack
- mb_chan_status_avail
- slimpro_mbox_irq
- slimpro_mbox_send_data
- slimpro_mbox_startup
- slimpro_mbox_shutdown
- slimpro_mbox_probe
- slimpro_mbox_init
- slimpro_mbox_exit
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 #include <linux/acpi.h>
   9 #include <linux/delay.h>
  10 #include <linux/interrupt.h>
  11 #include <linux/io.h>
  12 #include <linux/mailbox_controller.h>
  13 #include <linux/module.h>
  14 #include <linux/of.h>
  15 #include <linux/platform_device.h>
  16 #include <linux/spinlock.h>
  17 
  18 #define MBOX_CON_NAME                   "slimpro-mbox"
  19 #define MBOX_REG_SET_OFFSET             0x1000
  20 #define MBOX_CNT                        8
  21 #define MBOX_STATUS_AVAIL_MASK          BIT(16)
  22 #define MBOX_STATUS_ACK_MASK            BIT(0)
  23 
  24 
  25 #define REG_DB_IN               0x00
  26 #define REG_DB_DIN0             0x04
  27 #define REG_DB_DIN1             0x08
  28 #define REG_DB_OUT              0x10
  29 #define REG_DB_DOUT0            0x14
  30 #define REG_DB_DOUT1            0x18
  31 #define REG_DB_STAT             0x20
  32 #define REG_DB_STATMASK         0x24
  33 
  34 
  35 
  36 
  37 
  38 
  39 
  40 
  41 
  42 
  43 struct slimpro_mbox_chan {
  44         struct device           *dev;
  45         struct mbox_chan        *chan;
  46         void __iomem            *reg;
  47         int                     irq;
  48         u32                     rx_msg[3];
  49 };
  50 
  51 
  52 
  53 
  54 
  55 
  56 
  57 
  58 
  59 
  60 
  61 
  62 struct slimpro_mbox {
  63         struct mbox_controller          mb_ctrl;
  64         struct slimpro_mbox_chan        mc[MBOX_CNT];
  65         struct mbox_chan                chans[MBOX_CNT];
  66 };
  67 
  68 static void mb_chan_send_msg(struct slimpro_mbox_chan *mb_chan, u32 *msg)
  69 {
  70         writel(msg[1], mb_chan->reg + REG_DB_DOUT0);
  71         writel(msg[2], mb_chan->reg + REG_DB_DOUT1);
  72         writel(msg[0], mb_chan->reg + REG_DB_OUT);
  73 }
  74 
  75 static void mb_chan_recv_msg(struct slimpro_mbox_chan *mb_chan)
  76 {
  77         mb_chan->rx_msg[1] = readl(mb_chan->reg + REG_DB_DIN0);
  78         mb_chan->rx_msg[2] = readl(mb_chan->reg + REG_DB_DIN1);
  79         mb_chan->rx_msg[0] = readl(mb_chan->reg + REG_DB_IN);
  80 }
  81 
  82 static int mb_chan_status_ack(struct slimpro_mbox_chan *mb_chan)
  83 {
  84         u32 val = readl(mb_chan->reg + REG_DB_STAT);
  85 
  86         if (val & MBOX_STATUS_ACK_MASK) {
  87                 writel(MBOX_STATUS_ACK_MASK, mb_chan->reg + REG_DB_STAT);
  88                 return 1;
  89         }
  90         return 0;
  91 }
  92 
  93 static int mb_chan_status_avail(struct slimpro_mbox_chan *mb_chan)
  94 {
  95         u32 val = readl(mb_chan->reg + REG_DB_STAT);
  96 
  97         if (val & MBOX_STATUS_AVAIL_MASK) {
  98                 mb_chan_recv_msg(mb_chan);
  99                 writel(MBOX_STATUS_AVAIL_MASK, mb_chan->reg + REG_DB_STAT);
 100                 return 1;
 101         }
 102         return 0;
 103 }
 104 
 105 static irqreturn_t slimpro_mbox_irq(int irq, void *id)
 106 {
 107         struct slimpro_mbox_chan *mb_chan = id;
 108 
 109         if (mb_chan_status_ack(mb_chan))
 110                 mbox_chan_txdone(mb_chan->chan, 0);
 111 
 112         if (mb_chan_status_avail(mb_chan))
 113                 mbox_chan_received_data(mb_chan->chan, mb_chan->rx_msg);
 114 
 115         return IRQ_HANDLED;
 116 }
 117 
 118 static int slimpro_mbox_send_data(struct mbox_chan *chan, void *msg)
 119 {
 120         struct slimpro_mbox_chan *mb_chan = chan->con_priv;
 121 
 122         mb_chan_send_msg(mb_chan, msg);
 123         return 0;
 124 }
 125 
 126 static int slimpro_mbox_startup(struct mbox_chan *chan)
 127 {
 128         struct slimpro_mbox_chan *mb_chan = chan->con_priv;
 129         int rc;
 130         u32 val;
 131 
 132         rc = devm_request_irq(mb_chan->dev, mb_chan->irq, slimpro_mbox_irq, 0,
 133                               MBOX_CON_NAME, mb_chan);
 134         if (unlikely(rc)) {
 135                 dev_err(mb_chan->dev, "failed to register mailbox interrupt %d\n",
 136                         mb_chan->irq);
 137                 return rc;
 138         }
 139 
 140         
 141         writel(MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK,
 142                mb_chan->reg + REG_DB_STAT);
 143         
 144         val = readl(mb_chan->reg + REG_DB_STATMASK);
 145         val &= ~(MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK);
 146         writel(val, mb_chan->reg + REG_DB_STATMASK);
 147 
 148         return 0;
 149 }
 150 
 151 static void slimpro_mbox_shutdown(struct mbox_chan *chan)
 152 {
 153         struct slimpro_mbox_chan *mb_chan = chan->con_priv;
 154         u32 val;
 155 
 156         
 157         val = readl(mb_chan->reg + REG_DB_STATMASK);
 158         val |= (MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK);
 159         writel(val, mb_chan->reg + REG_DB_STATMASK);
 160 
 161         devm_free_irq(mb_chan->dev, mb_chan->irq, mb_chan);
 162 }
 163 
 164 static const struct mbox_chan_ops slimpro_mbox_ops = {
 165         .send_data = slimpro_mbox_send_data,
 166         .startup = slimpro_mbox_startup,
 167         .shutdown = slimpro_mbox_shutdown,
 168 };
 169 
 170 static int slimpro_mbox_probe(struct platform_device *pdev)
 171 {
 172         struct slimpro_mbox *ctx;
 173         struct resource *regs;
 174         void __iomem *mb_base;
 175         int rc;
 176         int i;
 177 
 178         ctx = devm_kzalloc(&pdev->dev, sizeof(struct slimpro_mbox), GFP_KERNEL);
 179         if (!ctx)
 180                 return -ENOMEM;
 181 
 182         platform_set_drvdata(pdev, ctx);
 183 
 184         regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 185         mb_base = devm_ioremap_resource(&pdev->dev, regs);
 186         if (IS_ERR(mb_base))
 187                 return PTR_ERR(mb_base);
 188 
 189         
 190         for (i = 0; i < MBOX_CNT; i++) {
 191                 ctx->mc[i].irq = platform_get_irq(pdev, i);
 192                 if (ctx->mc[i].irq < 0) {
 193                         if (i == 0) {
 194                                 dev_err(&pdev->dev, "no available IRQ\n");
 195                                 return -EINVAL;
 196                         }
 197                         dev_info(&pdev->dev, "no IRQ for channel %d\n", i);
 198                         break;
 199                 }
 200 
 201                 ctx->mc[i].dev = &pdev->dev;
 202                 ctx->mc[i].reg = mb_base + i * MBOX_REG_SET_OFFSET;
 203                 ctx->mc[i].chan = &ctx->chans[i];
 204                 ctx->chans[i].con_priv = &ctx->mc[i];
 205         }
 206 
 207         
 208         ctx->mb_ctrl.dev = &pdev->dev;
 209         ctx->mb_ctrl.chans = ctx->chans;
 210         ctx->mb_ctrl.txdone_irq = true;
 211         ctx->mb_ctrl.ops = &slimpro_mbox_ops;
 212         ctx->mb_ctrl.num_chans = i;
 213 
 214         rc = devm_mbox_controller_register(&pdev->dev, &ctx->mb_ctrl);
 215         if (rc) {
 216                 dev_err(&pdev->dev,
 217                         "APM X-Gene SLIMpro MailBox register failed:%d\n", rc);
 218                 return rc;
 219         }
 220 
 221         dev_info(&pdev->dev, "APM X-Gene SLIMpro MailBox registered\n");
 222         return 0;
 223 }
 224 
 225 static const struct of_device_id slimpro_of_match[] = {
 226         {.compatible = "apm,xgene-slimpro-mbox" },
 227         { },
 228 };
 229 MODULE_DEVICE_TABLE(of, slimpro_of_match);
 230 
 231 #ifdef CONFIG_ACPI
 232 static const struct acpi_device_id slimpro_acpi_ids[] = {
 233         {"APMC0D01", 0},
 234         {}
 235 };
 236 MODULE_DEVICE_TABLE(acpi, slimpro_acpi_ids);
 237 #endif
 238 
 239 static struct platform_driver slimpro_mbox_driver = {
 240         .probe  = slimpro_mbox_probe,
 241         .driver = {
 242                 .name = "xgene-slimpro-mbox",
 243                 .of_match_table = of_match_ptr(slimpro_of_match),
 244                 .acpi_match_table = ACPI_PTR(slimpro_acpi_ids)
 245         },
 246 };
 247 
 248 static int __init slimpro_mbox_init(void)
 249 {
 250         return platform_driver_register(&slimpro_mbox_driver);
 251 }
 252 
 253 static void __exit slimpro_mbox_exit(void)
 254 {
 255         platform_driver_unregister(&slimpro_mbox_driver);
 256 }
 257 
 258 subsys_initcall(slimpro_mbox_init);
 259 module_exit(slimpro_mbox_exit);
 260 
 261 MODULE_DESCRIPTION("APM X-Gene SLIMpro Mailbox Driver");
 262 MODULE_LICENSE("GPL");