18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III 38c2ecf20Sopenharmony_ci * platforms. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net) 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/types.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/sched.h> 138c2ecf20Sopenharmony_ci#include <linux/wait.h> 148c2ecf20Sopenharmony_ci#include <linux/delay.h> 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci#include <linux/of.h> 178c2ecf20Sopenharmony_ci#include <linux/of_device.h> 188c2ecf20Sopenharmony_ci#include <asm/bbc.h> 198c2ecf20Sopenharmony_ci#include <asm/io.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "bbc_i2c.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* Convert this driver to use i2c bus layer someday... */ 248c2ecf20Sopenharmony_ci#define I2C_PCF_PIN 0x80 258c2ecf20Sopenharmony_ci#define I2C_PCF_ESO 0x40 268c2ecf20Sopenharmony_ci#define I2C_PCF_ES1 0x20 278c2ecf20Sopenharmony_ci#define I2C_PCF_ES2 0x10 288c2ecf20Sopenharmony_ci#define I2C_PCF_ENI 0x08 298c2ecf20Sopenharmony_ci#define I2C_PCF_STA 0x04 308c2ecf20Sopenharmony_ci#define I2C_PCF_STO 0x02 318c2ecf20Sopenharmony_ci#define I2C_PCF_ACK 0x01 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define I2C_PCF_START (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ENI | I2C_PCF_STA | I2C_PCF_ACK) 348c2ecf20Sopenharmony_ci#define I2C_PCF_STOP (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK) 358c2ecf20Sopenharmony_ci#define I2C_PCF_REPSTART ( I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK) 368c2ecf20Sopenharmony_ci#define I2C_PCF_IDLE (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ACK) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define I2C_PCF_INI 0x40 /* 1 if not initialized */ 398c2ecf20Sopenharmony_ci#define I2C_PCF_STS 0x20 408c2ecf20Sopenharmony_ci#define I2C_PCF_BER 0x10 418c2ecf20Sopenharmony_ci#define I2C_PCF_AD0 0x08 428c2ecf20Sopenharmony_ci#define I2C_PCF_LRB 0x08 438c2ecf20Sopenharmony_ci#define I2C_PCF_AAS 0x04 448c2ecf20Sopenharmony_ci#define I2C_PCF_LAB 0x02 458c2ecf20Sopenharmony_ci#define I2C_PCF_BB 0x01 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* The BBC devices have two I2C controllers. The first I2C controller 488c2ecf20Sopenharmony_ci * connects mainly to configuration proms (NVRAM, cpu configuration, 498c2ecf20Sopenharmony_ci * dimm types, etc.). Whereas the second I2C controller connects to 508c2ecf20Sopenharmony_ci * environmental control devices such as fans and temperature sensors. 518c2ecf20Sopenharmony_ci * The second controller also connects to the smartcard reader, if present. 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic void set_device_claimage(struct bbc_i2c_bus *bp, struct platform_device *op, int val) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci int i; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci for (i = 0; i < NUM_CHILDREN; i++) { 598c2ecf20Sopenharmony_ci if (bp->devs[i].device == op) { 608c2ecf20Sopenharmony_ci bp->devs[i].client_claimed = val; 618c2ecf20Sopenharmony_ci return; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#define claim_device(BP,ECHILD) set_device_claimage(BP,ECHILD,1) 678c2ecf20Sopenharmony_ci#define release_device(BP,ECHILD) set_device_claimage(BP,ECHILD,0) 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistruct platform_device *bbc_i2c_getdev(struct bbc_i2c_bus *bp, int index) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci struct platform_device *op = NULL; 728c2ecf20Sopenharmony_ci int curidx = 0, i; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci for (i = 0; i < NUM_CHILDREN; i++) { 758c2ecf20Sopenharmony_ci if (!(op = bp->devs[i].device)) 768c2ecf20Sopenharmony_ci break; 778c2ecf20Sopenharmony_ci if (curidx == index) 788c2ecf20Sopenharmony_ci goto out; 798c2ecf20Sopenharmony_ci op = NULL; 808c2ecf20Sopenharmony_ci curidx++; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ciout: 848c2ecf20Sopenharmony_ci if (curidx == index) 858c2ecf20Sopenharmony_ci return op; 868c2ecf20Sopenharmony_ci return NULL; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistruct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct platform_device *op) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci struct bbc_i2c_client *client; 928c2ecf20Sopenharmony_ci const u32 *reg; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci client = kzalloc(sizeof(*client), GFP_KERNEL); 958c2ecf20Sopenharmony_ci if (!client) 968c2ecf20Sopenharmony_ci return NULL; 978c2ecf20Sopenharmony_ci client->bp = bp; 988c2ecf20Sopenharmony_ci client->op = op; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci reg = of_get_property(op->dev.of_node, "reg", NULL); 1018c2ecf20Sopenharmony_ci if (!reg) { 1028c2ecf20Sopenharmony_ci kfree(client); 1038c2ecf20Sopenharmony_ci return NULL; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci client->bus = reg[0]; 1078c2ecf20Sopenharmony_ci client->address = reg[1]; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci claim_device(bp, op); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return client; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_civoid bbc_i2c_detach(struct bbc_i2c_client *client) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct bbc_i2c_bus *bp = client->bp; 1178c2ecf20Sopenharmony_ci struct platform_device *op = client->op; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci release_device(bp, op); 1208c2ecf20Sopenharmony_ci kfree(client); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic int wait_for_pin(struct bbc_i2c_bus *bp, u8 *status) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 1268c2ecf20Sopenharmony_ci int limit = 32; 1278c2ecf20Sopenharmony_ci int ret = 1; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci bp->waiting = 1; 1308c2ecf20Sopenharmony_ci add_wait_queue(&bp->wq, &wait); 1318c2ecf20Sopenharmony_ci while (limit-- > 0) { 1328c2ecf20Sopenharmony_ci long val; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci val = wait_event_interruptible_timeout( 1358c2ecf20Sopenharmony_ci bp->wq, 1368c2ecf20Sopenharmony_ci (((*status = readb(bp->i2c_control_regs + 0)) 1378c2ecf20Sopenharmony_ci & I2C_PCF_PIN) == 0), 1388c2ecf20Sopenharmony_ci msecs_to_jiffies(250)); 1398c2ecf20Sopenharmony_ci if (val > 0) { 1408c2ecf20Sopenharmony_ci ret = 0; 1418c2ecf20Sopenharmony_ci break; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci remove_wait_queue(&bp->wq, &wait); 1458c2ecf20Sopenharmony_ci bp->waiting = 0; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci return ret; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ciint bbc_i2c_writeb(struct bbc_i2c_client *client, unsigned char val, int off) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci struct bbc_i2c_bus *bp = client->bp; 1538c2ecf20Sopenharmony_ci int address = client->address; 1548c2ecf20Sopenharmony_ci u8 status; 1558c2ecf20Sopenharmony_ci int ret = -1; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (bp->i2c_bussel_reg != NULL) 1588c2ecf20Sopenharmony_ci writeb(client->bus, bp->i2c_bussel_reg); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci writeb(address, bp->i2c_control_regs + 0x1); 1618c2ecf20Sopenharmony_ci writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0); 1628c2ecf20Sopenharmony_ci if (wait_for_pin(bp, &status)) 1638c2ecf20Sopenharmony_ci goto out; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci writeb(off, bp->i2c_control_regs + 0x1); 1668c2ecf20Sopenharmony_ci if (wait_for_pin(bp, &status) || 1678c2ecf20Sopenharmony_ci (status & I2C_PCF_LRB) != 0) 1688c2ecf20Sopenharmony_ci goto out; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci writeb(val, bp->i2c_control_regs + 0x1); 1718c2ecf20Sopenharmony_ci if (wait_for_pin(bp, &status)) 1728c2ecf20Sopenharmony_ci goto out; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci ret = 0; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ciout: 1778c2ecf20Sopenharmony_ci writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0); 1788c2ecf20Sopenharmony_ci return ret; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ciint bbc_i2c_readb(struct bbc_i2c_client *client, unsigned char *byte, int off) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct bbc_i2c_bus *bp = client->bp; 1848c2ecf20Sopenharmony_ci unsigned char address = client->address, status; 1858c2ecf20Sopenharmony_ci int ret = -1; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (bp->i2c_bussel_reg != NULL) 1888c2ecf20Sopenharmony_ci writeb(client->bus, bp->i2c_bussel_reg); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci writeb(address, bp->i2c_control_regs + 0x1); 1918c2ecf20Sopenharmony_ci writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0); 1928c2ecf20Sopenharmony_ci if (wait_for_pin(bp, &status)) 1938c2ecf20Sopenharmony_ci goto out; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci writeb(off, bp->i2c_control_regs + 0x1); 1968c2ecf20Sopenharmony_ci if (wait_for_pin(bp, &status) || 1978c2ecf20Sopenharmony_ci (status & I2C_PCF_LRB) != 0) 1988c2ecf20Sopenharmony_ci goto out; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci address |= 0x1; /* READ */ 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci writeb(address, bp->i2c_control_regs + 0x1); 2058c2ecf20Sopenharmony_ci writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0); 2068c2ecf20Sopenharmony_ci if (wait_for_pin(bp, &status)) 2078c2ecf20Sopenharmony_ci goto out; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* Set PIN back to one so the device sends the first 2108c2ecf20Sopenharmony_ci * byte. 2118c2ecf20Sopenharmony_ci */ 2128c2ecf20Sopenharmony_ci (void) readb(bp->i2c_control_regs + 0x1); 2138c2ecf20Sopenharmony_ci if (wait_for_pin(bp, &status)) 2148c2ecf20Sopenharmony_ci goto out; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci writeb(I2C_PCF_ESO | I2C_PCF_ENI, bp->i2c_control_regs + 0x0); 2178c2ecf20Sopenharmony_ci *byte = readb(bp->i2c_control_regs + 0x1); 2188c2ecf20Sopenharmony_ci if (wait_for_pin(bp, &status)) 2198c2ecf20Sopenharmony_ci goto out; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci ret = 0; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ciout: 2248c2ecf20Sopenharmony_ci writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0); 2258c2ecf20Sopenharmony_ci (void) readb(bp->i2c_control_regs + 0x1); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return ret; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ciint bbc_i2c_write_buf(struct bbc_i2c_client *client, 2318c2ecf20Sopenharmony_ci char *buf, int len, int off) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci int ret = 0; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci while (len > 0) { 2368c2ecf20Sopenharmony_ci ret = bbc_i2c_writeb(client, *buf, off); 2378c2ecf20Sopenharmony_ci if (ret < 0) 2388c2ecf20Sopenharmony_ci break; 2398c2ecf20Sopenharmony_ci len--; 2408c2ecf20Sopenharmony_ci buf++; 2418c2ecf20Sopenharmony_ci off++; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci return ret; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ciint bbc_i2c_read_buf(struct bbc_i2c_client *client, 2478c2ecf20Sopenharmony_ci char *buf, int len, int off) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci int ret = 0; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci while (len > 0) { 2528c2ecf20Sopenharmony_ci ret = bbc_i2c_readb(client, buf, off); 2538c2ecf20Sopenharmony_ci if (ret < 0) 2548c2ecf20Sopenharmony_ci break; 2558c2ecf20Sopenharmony_ci len--; 2568c2ecf20Sopenharmony_ci buf++; 2578c2ecf20Sopenharmony_ci off++; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci return ret; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bbc_i2c_getdev); 2648c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bbc_i2c_attach); 2658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bbc_i2c_detach); 2668c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bbc_i2c_writeb); 2678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bbc_i2c_readb); 2688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bbc_i2c_write_buf); 2698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bbc_i2c_read_buf); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic irqreturn_t bbc_i2c_interrupt(int irq, void *dev_id) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct bbc_i2c_bus *bp = dev_id; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* PIN going from set to clear is the only event which 2768c2ecf20Sopenharmony_ci * makes the i2c assert an interrupt. 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_ci if (bp->waiting && 2798c2ecf20Sopenharmony_ci !(readb(bp->i2c_control_regs + 0x0) & I2C_PCF_PIN)) 2808c2ecf20Sopenharmony_ci wake_up_interruptible(&bp->wq); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic void reset_one_i2c(struct bbc_i2c_bus *bp) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci writeb(I2C_PCF_PIN, bp->i2c_control_regs + 0x0); 2888c2ecf20Sopenharmony_ci writeb(bp->own, bp->i2c_control_regs + 0x1); 2898c2ecf20Sopenharmony_ci writeb(I2C_PCF_PIN | I2C_PCF_ES1, bp->i2c_control_regs + 0x0); 2908c2ecf20Sopenharmony_ci writeb(bp->clock, bp->i2c_control_regs + 0x1); 2918c2ecf20Sopenharmony_ci writeb(I2C_PCF_IDLE, bp->i2c_control_regs + 0x0); 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic struct bbc_i2c_bus * attach_one_i2c(struct platform_device *op, int index) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct bbc_i2c_bus *bp; 2978c2ecf20Sopenharmony_ci struct device_node *dp; 2988c2ecf20Sopenharmony_ci int entry; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci bp = kzalloc(sizeof(*bp), GFP_KERNEL); 3018c2ecf20Sopenharmony_ci if (!bp) 3028c2ecf20Sopenharmony_ci return NULL; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bp->temps); 3058c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bp->fans); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci bp->i2c_control_regs = of_ioremap(&op->resource[0], 0, 0x2, "bbc_i2c_regs"); 3088c2ecf20Sopenharmony_ci if (!bp->i2c_control_regs) 3098c2ecf20Sopenharmony_ci goto fail; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (op->num_resources == 2) { 3128c2ecf20Sopenharmony_ci bp->i2c_bussel_reg = of_ioremap(&op->resource[1], 0, 0x1, "bbc_i2c_bussel"); 3138c2ecf20Sopenharmony_ci if (!bp->i2c_bussel_reg) 3148c2ecf20Sopenharmony_ci goto fail; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci bp->waiting = 0; 3188c2ecf20Sopenharmony_ci init_waitqueue_head(&bp->wq); 3198c2ecf20Sopenharmony_ci if (request_irq(op->archdata.irqs[0], bbc_i2c_interrupt, 3208c2ecf20Sopenharmony_ci IRQF_SHARED, "bbc_i2c", bp)) 3218c2ecf20Sopenharmony_ci goto fail; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci bp->index = index; 3248c2ecf20Sopenharmony_ci bp->op = op; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci spin_lock_init(&bp->lock); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci entry = 0; 3298c2ecf20Sopenharmony_ci for (dp = op->dev.of_node->child; 3308c2ecf20Sopenharmony_ci dp && entry < 8; 3318c2ecf20Sopenharmony_ci dp = dp->sibling, entry++) { 3328c2ecf20Sopenharmony_ci struct platform_device *child_op; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci child_op = of_find_device_by_node(dp); 3358c2ecf20Sopenharmony_ci bp->devs[entry].device = child_op; 3368c2ecf20Sopenharmony_ci bp->devs[entry].client_claimed = 0; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci writeb(I2C_PCF_PIN, bp->i2c_control_regs + 0x0); 3408c2ecf20Sopenharmony_ci bp->own = readb(bp->i2c_control_regs + 0x01); 3418c2ecf20Sopenharmony_ci writeb(I2C_PCF_PIN | I2C_PCF_ES1, bp->i2c_control_regs + 0x0); 3428c2ecf20Sopenharmony_ci bp->clock = readb(bp->i2c_control_regs + 0x01); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci printk(KERN_INFO "i2c-%d: Regs at %p, %d devices, own %02x, clock %02x.\n", 3458c2ecf20Sopenharmony_ci bp->index, bp->i2c_control_regs, entry, bp->own, bp->clock); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci reset_one_i2c(bp); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci return bp; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cifail: 3528c2ecf20Sopenharmony_ci if (bp->i2c_bussel_reg) 3538c2ecf20Sopenharmony_ci of_iounmap(&op->resource[1], bp->i2c_bussel_reg, 1); 3548c2ecf20Sopenharmony_ci if (bp->i2c_control_regs) 3558c2ecf20Sopenharmony_ci of_iounmap(&op->resource[0], bp->i2c_control_regs, 2); 3568c2ecf20Sopenharmony_ci kfree(bp); 3578c2ecf20Sopenharmony_ci return NULL; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ciextern int bbc_envctrl_init(struct bbc_i2c_bus *bp); 3618c2ecf20Sopenharmony_ciextern void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic int bbc_i2c_probe(struct platform_device *op) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci struct bbc_i2c_bus *bp; 3668c2ecf20Sopenharmony_ci int err, index = 0; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci bp = attach_one_i2c(op, index); 3698c2ecf20Sopenharmony_ci if (!bp) 3708c2ecf20Sopenharmony_ci return -EINVAL; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci err = bbc_envctrl_init(bp); 3738c2ecf20Sopenharmony_ci if (err) { 3748c2ecf20Sopenharmony_ci free_irq(op->archdata.irqs[0], bp); 3758c2ecf20Sopenharmony_ci if (bp->i2c_bussel_reg) 3768c2ecf20Sopenharmony_ci of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1); 3778c2ecf20Sopenharmony_ci if (bp->i2c_control_regs) 3788c2ecf20Sopenharmony_ci of_iounmap(&op->resource[1], bp->i2c_control_regs, 2); 3798c2ecf20Sopenharmony_ci kfree(bp); 3808c2ecf20Sopenharmony_ci } else { 3818c2ecf20Sopenharmony_ci dev_set_drvdata(&op->dev, bp); 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci return err; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic int bbc_i2c_remove(struct platform_device *op) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci struct bbc_i2c_bus *bp = dev_get_drvdata(&op->dev); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci bbc_envctrl_cleanup(bp); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci free_irq(op->archdata.irqs[0], bp); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (bp->i2c_bussel_reg) 3968c2ecf20Sopenharmony_ci of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1); 3978c2ecf20Sopenharmony_ci if (bp->i2c_control_regs) 3988c2ecf20Sopenharmony_ci of_iounmap(&op->resource[1], bp->i2c_control_regs, 2); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci kfree(bp); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci return 0; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic const struct of_device_id bbc_i2c_match[] = { 4068c2ecf20Sopenharmony_ci { 4078c2ecf20Sopenharmony_ci .name = "i2c", 4088c2ecf20Sopenharmony_ci .compatible = "SUNW,bbc-i2c", 4098c2ecf20Sopenharmony_ci }, 4108c2ecf20Sopenharmony_ci {}, 4118c2ecf20Sopenharmony_ci}; 4128c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, bbc_i2c_match); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic struct platform_driver bbc_i2c_driver = { 4158c2ecf20Sopenharmony_ci .driver = { 4168c2ecf20Sopenharmony_ci .name = "bbc_i2c", 4178c2ecf20Sopenharmony_ci .of_match_table = bbc_i2c_match, 4188c2ecf20Sopenharmony_ci }, 4198c2ecf20Sopenharmony_ci .probe = bbc_i2c_probe, 4208c2ecf20Sopenharmony_ci .remove = bbc_i2c_remove, 4218c2ecf20Sopenharmony_ci}; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cimodule_platform_driver(bbc_i2c_driver); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 426